第三章 了解 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
Array re-loaded from YAML string:
[1, 2, 3, [4, "five", :six]]
Rails 在几种上下文中使用 YAML,在 database.yml 中会看到如下的块:
development:
将这些行放到一个文件(如sample.yml)中,然后运行下面命令:
F:\ruby_project>ruby -ryaml -e 'p YAML.load(File.read("sample.rb"))'
{"development" => {"socket"=>"/tmp/mysql.sock",
}
二、给控制器增加功能
通过点击合适的列标题,可以让列表以不同的方式排序(按标题,按作者,按状态):
def all
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)
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
end
2. 自由形式的编程的模型改进
假设在一个视图模板中,变量@customer包含一个客户对象,你可以像下面这样显示这个人的名字:
<p>Hello, <%= @customer.title + " " + @customer.first_name + " " +
下面让 customer 对象自己产生该名字的友好板本:
class Customer < ActiveRecord::Base
end
下面可以在视图中直接调用 @customer 中该实例的方法:
<p>Good morning, <%= @customer.nice_name %>.</p>