天天看點

Ruby for Rails 最佳實踐Ⅲ

第三章 了解 Ruby 前提下的 Rails 開發

一、YAML 和實際為程式設計的配置

YAML (按 UNIX 平台的傳統,最初代表 Yet Another Markup Language,現在卻代表 YAML Ain’t Markup Language)可以說是一個标記語言,也可以說是一個串行化格式,取決于你看問題的角度。下面是一個簡單的例子:一個嵌套的數組結構轉變成一個 YAML 表示,然後再由它恢複成一個數組:

require 'yaml'

array = [1, 2, 3, [4, "five", :six]]

puts "Original array:"

puts array.inspect

yarray = array.to_yaml

puts "YAML representation of array: "

puts yarray

thawed = YAML.load(yarray)

puts "Array re-loaded from YAML string: "

p thawed

(此例中,inspect 方法為對象産生一個詳細的字元串表示;還有 p 方法,等價于 puts)。

運作這段腳本的輸出如下:

Original array:

[1, 2, 3, [4, "five", :six]]

YAML representation of array:

---

- 1

- 2

- 3

- - 4

  - five

  - :six

Array re-loaded from YAML string:

[1, 2, 3, [4, "five", :six]]

Rails 在幾種上下文中使用 YAML,在 database.yml 中會看到如下的塊:

development:

  adapter: mysql

  database: r4rmusic1_development

  username: r4r

  password: railzrulez

  socket: /tmp/mysql.sock

将這些行放到一個檔案(如sample.yml)中,然後運作下面指令:

F:\ruby_project>ruby -ryaml -e 'p YAML.load(File.read("sample.rb"))'

{"development" => {"socket"=>"/tmp/mysql.sock",

                   "username"=>"r4r",

                   "adapter"=>"mysql",

                   "password"=>"railzrulez",

                   "database"=>"r4rmusic1_development"

                   }

}

二、給控制器增加功能

通過點選合适的列标題,可以讓清單以不同的方式排序(按标題,按作者,按狀态):

def all

  @order = params[:order] || "number"

  sort_proc = case @order

    when "author"  then lambda {|r| [r.user.name.downcase, r.number] }

    when "status",

         "title"   then lambda {|r| [r.send(@order).downcase, r.number]}

    when "number"  then lambda {|r| -r.number }

  end

  @rcrs = Rcr.find(:all).sort_by &sort_proc

end

變量@order(一個執行個體變量)設定為CGI變量order的值;如果該CGI變量的值沒有設定,則它的預設值是字元串"number"。然後,變量sort_proc(排序過程)被設定為三個可能的lambda表達式(匿名函數)中的一個。選擇哪一個lambda表達式取決于@order的值,這個選擇是通過一個case語句來執行的。

一旦標明了正确的lambda表達式,所有現存的RCR将根據該lambda表達式的邏輯排序,這個排序需使用ActiveRecord的find方法來擷取所有的RCR,以及根據sort_proc中儲存的lambda表達式來使用Ruby的sort_by方法過濾這個清單。

如果了解Ruby,則該方法很容易編寫。但是一定要了解Ruby!确切地說,需要了解下面這些内容:

case語句;

lambda關鍵字,用它生成一個匿名函數;

send方法(請注意status和title是怎樣一起處理的);

sort_by方法,需要給它傳遞一個lambda表達式。

三、部署 Rails 的輔助檔案

Rails 對每一個控制器都會自動産生一個輔助檔案,可以編寫任意多的 Ruby 方法。位于 app\helpers 下。

下面是一個從RCRchive清單排序代碼中提取的例子。在RCR的每一個視圖中的每一個列标題,都超連結到rcr/all動作。這些連結隻在一個方面有差別:order參數的值(“author”、“title”、“number”或“Status”)。這意味着這四個連結使用幾乎完全相同的代碼。為減少重複,可用一個輔助方法自動産生合适的連結。你所需要做的僅僅是傳遞給它一個order參數。

該輔助方法定義在檔案rcr_helper.rb中,如下所示:

def link_to_order(order)

  link_to(order.capitalize,

          :controller => "rcr",

          :action     => "all",

          :params     => { "order" => order })

end

在視圖(app/views/rcr/all.rhtml)中,下面四行産生表的列标題:

<th class="rcr"><%= link_to_order("number") %></th>

<th class="rcr"><%= link_to_order("title") %></th>

<th class="rcr"><%= link_to_order("status") %></th>

<th class="rcr"><%= link_to_order("author") %></th>

四、給模型增加功能

1. 實作預定義的回調方法

如果在一個ActiveRecord模型檔案中編寫一個名為before_create的方法,該方法會在該模型的執行個體的資料庫記錄産生之前被執行。

如果description字段有預設的字元串值,那應該更好。如果在資料庫記錄首次産生的時候,該edition不存在描述資訊,讓我們給它一個預設值"standard"。

def before_create

  self.description = "standard" unless description

end

2. 自由形式的程式設計的模型改進

假設在一個視圖模闆中,變量@customer包含一個客戶對象,你可以像下面這樣顯示這個人的名字:

<p>Hello, <%= @customer.title + " " + @customer.first_name + " " +

              @customer.middle_initial + ". " +

              @customer.last_name" %></p>

下面讓 customer 對象自己産生該名字的友好闆本:

class Customer < ActiveRecord::Base

  def nice_name

    title + " " + first_name + " " +

      (if middle_initial then middle_initial + ". " else "" end) +

      last_name

  end

end

下面可以在視圖中直接調用 @customer 中該執行個體的方法:

<p>Good morning, <%= @customer.nice_name %>.</p>