關於編碼


先前的例子都使用英文訊息,如果要在Rails中使用中文,要先知道的是,Rails使用Ruby語言,所以你必須先有Ruby 1.9.2的編碼基礎,可參考 Ruby 學習筆記 中的 關於編碼。以下將記錄Rails中有關編碼的一些設定。

首先要知道的是,Rails 3.1整體預設是使用UTF-8,包括內部編碼、外部編碼與Content-Type標頭(Header)設定等。

在Ubuntu中,由於所有的檔案預設編碼都是UTF-8,所以如果在.html.erb中直接撰寫中文,例如:

  • index.html.erb
<h1>線上書籤</h1>
<ul>
  <% @pages.each do |page| %>
    <li>
      <%= link_to page.title, page.url %>
      <%= button_to "內容", bookmark_path(page), :method => :get %>
      <%= button_to "編輯", edit_bookmark_path(page), :method => :get %>
      <%= button_to "刪除", bookmark_path(page), :method => :delete %>
    </li>
  <% end %>
</ul>
<%= link_to "新增", new_bookmark_path %>

瀏覽器必須使用UTF-8編碼觀看,才會出現正確的中文,Rails 3.1預設會丟Content-Type的標頭給瀏覽器,值為text/html; charset=utf-8,所以瀏覽器就會依指示自動選用UTF-8來呈現頁面,如果是發送請求參數,也是用UTF-8來解釋。

如果要在.rb檔案中撰寫中文,由於在Ubuntu中,預設就是使用UTF-8編寫檔案,在Ruby 1.9.2中,必須在.rb開頭加上:

# encoding: UTF-8

如此在.rb中撰寫中文,才不會發生直譯錯誤。

如果是在中文Windows中,你以個別新增文字檔案的方式,由於中文Windows中文字檔案預設是MS950(相容於Big5),要輸出中文最簡單的方式,就是改用可指定UTF-8的編輯器來編寫.html.erb或.rb,則注意事項如上所述。

對於新開發的專案,建議整個應用程式使用UTF-8,以避免各種編碼轉換的問題,如果要改用別的編碼比較麻煩,不過以下藉此瞭解一下Rails中有關編碼的設定,若你不想瞭解以下編碼事宜,那就全部UTF-8吧!

以下先說明在.html.erb或.rb撰寫中文,要注意的事項。假設因為某些原因,你真的要使用Big5(或其它編碼)來編寫頁面,如果是.html.erb,得在檔案開頭加上:

# encoding: Big5

這指定Rails在讀取.html.erb時,必須使用Big5來讀取,在.html.erb後撰寫的字串會編碼為UTF-8,Rails預設內部編碼與外部編碼都是UTF-8,仍是丟Content-Type為text/html; charset=utf-8,瀏覽器顯示時也就預設挑選UTF-8編碼,發送請求參數時還是使用UTF-8來解釋。

由於如上設定後,Rails的外部編碼也是UTF-8,,因此.rb檔若也設定為# encoding: Big5(會使得.rb中撰寫的字串為Big5編碼),則在顯示頁面會發生incompatible character encodings: UTF-8 and Big5的錯誤,你反而要在.rb檔中設定# encoding: UTF-8(.rb也必須是UTF-8編碼),才不會在顯示頁面時發生錯誤,當然.rb是UTF-8,而.html.erb是Big5,應用程式編碼不一致並不是好事。

可以修改config/application.rb的設定:

  • application.rb
config.encoding = "big5" # 預設是"utf-8"

則Rails會使用Big5讀取.html.erb(不用在個別.html.erb中加入# encoding: Big5),撰寫的字串使用Big5編碼,內部編碼與外部編碼都是Big5,所以.rb就可以使用Big5編寫,並於檔案中設置#encoding: Big5,然而Rails仍是丟Content-Type為text/html; charset=utf-8,所以你得自己在瀏覽器中選擇使用Big5顯示,才可以看到中文。

可以在控制器的每個動作之前,加上過濾器設置標頭。例如:

  • bookmarks_controller.rb
class BookmarksController < ApplicationController
    before_filter :set_content_type
    
def set_content_type
headers["Content-Type"] = "text/html; charset=big5" # 設定HTTP回應的Content-Type標頭
end

...略
end

如此瀏覽器就會依標頭提示,選用Big5來顯示頁面。如果每個控制器都需要這個設定,可以改設在ApplicationController中,也就是打開application_controller.rb:

  • application_controller.rb
class ApplicationController < ActionController::Base
    protect_from_forgery
    before_filter :set_content_type
    
    def set_content_type
        response.headers["Content-Type"] = "text/html; charset=big5"
    end  
end


關於請求參數,Rails預期收到UTF-8字串的URL編碼,例如若要發送「測」這個字,必須編碼為%E6%B8%AC,如果是透過Rails的輔助方法產生鏈結或發送表單,Rails會透過Ajax發送請求參數,因為JavaScript內部都是使用UTF-8,透過Ajax發送的請求,也會自動作URL編碼,所以基本上你不用親自處理URL編碼。

如果application.rb中的config.encoding設定為UTF-8,則Rails會將收到的請求參數編碼為UTF-8的字串,如果config.encoding設定為Big5,則Rails會將收到的請求參數編碼為Big5的字串。

資料庫的部份,如果是SQLite,預設是UTF-8,如果config.encoding設定為UTF-8,則合法UTF-8字串存入資料庫自然沒有問題,從資料庫取回的文字也會編碼為UTF-8字串,如果config.encoding設定為Big5,則合法的Big5字串存入資料庫時,會自動轉為UTF-8再存入資料庫,從資料庫中取回文字時,會編碼為Big5字串。

如果資料庫編碼不是UTF-8,則可以在config/database.yml中設定encoding。例如若MySQL資料庫採用Big5,則可以如下:
  • database.yml
development:
  adapter: mysql
  encoding: big5
  database: bookmark_development
  username: root
  password:
production:
  adapter: mysql
  encoding: big5
  database: bookmark_production
  username: root
  password:
test:
  adapter: mysql
  encoding: big5
  database: bookmark_test
  username: root
  password: