Rails Cookbook读书笔记之-Understanding Pluralization Patterns in Rails

来源:互联网 发布:查询qq陌生人网络状态 编辑:程序博客网 时间:2024/04/28 23:29

只看上面的标题名字,还以为要学习什么英文语法,其实不然。单词的复数使用是Rails中的语法要求(语法习惯Rails relies heavily on convention),这个要求适合英语作为母语的开发人员,让程序语言也按照英语语法进行表达,使程序员很容易理解代码和上下文环境(The intent of pluralization is to make your code more readable and transparent)。

首先,在Rails中模块和控制器用单数表示,而对应的数据库表用复数表示。这很好理解,因为控制器和模块在运行时都是代表对一条数据的控制和持有,而数据库表将存储多条数据。下面有个列表具体指出什么地方可以用复数,什么地方不能使用。

数据库表的名字(Database table names: plural 复数

模块类名(Model class names: singular 单数

控制器类名(Controller class names: plural 复数

?原书是用复数,但我用单数也可以运行;

遵循上面的约定对于正确使用Rails是大有帮助的。下面看一个一对多的例子:chapters and recipes

app/models/chapter.rb:

class Chapter < ActiveRecord::Base
  has_many :recipes
end

上面是模块类Chapter的定义,注意文件名和类名都是单数。“has_many :recipes”的意思很好理解:Chapter 有一个或多个recipes对应。注意这里的recipes是复数。程序语言的语法很像英语语法,方便了不懂程序语言的人阅读。当然还要注意使用复数的目录名和文件名如:视图VIEW的目录名,函数(functional)、单元测试、测试套件(fixture)的文件名。最好的方法就是实验一下,用下面的命令:

>ruby script/generate scaffold -p recipe
 

-ppretend选项显示创建的详细,但并没有实际创建文件,只是提前给你参考。如果你不想用这样的方式去查看单复数的转换,可以使用Geoffrey Grosenbach 提供的在线工具http://nubyonrails.com/tools/pluralize

Rails中的“约定”主要是用来消除一些繁琐的配置,当然也不是所有的人都领情,争论肯定是有的。如果你想使项目中 “约定”失效,可以更改项目中的配置文件:

config/environment.rb:

ActiveRecord::Base.pluralize_table_names = false

 

还有一个比较重要的问题是英文单词如何变形,Rails 定义了一个确定单词如何变为复数的类Inflections,这个类定义了几个方法并且被mixed(是Ruby实现多重继承的方式)到String类中,保证所有String对象都可以使用这些方法,如方法pluralize

> ruby script/console

Loading development environment.

>> "account".pluralize

=> "accounts"

>> "people".pluralize

=> "peoples"

Rails是如何进行变形?实现非常简单,在ActiveSupport gem 库中有一个变形规则表文件inflections.rb,下面是这个文件的部分内容:

activesupport-1.3.1/lib/active_support/inflections.rb:

Inflector.inflections do |inflect|
  inflect.plural(/$/, 's')
  inflect.plural(/s$/i, 's')
  inflect.plural(/(ax|test)is$/i, '/1es') 
 
  ...
 
  inflect.singular(/s$/i, '')
  inflect.singular(/(n)ews$/i, '/1ews')
  inflect.singular(/([ti])a$/i, '/1um')
   
  ...
 
  inflect.irregular('person', 'people')
  inflect.irregular('man', 'men')
  inflect.irregular('child', 'children')
 
  ...
 
  inflect.uncountable(%w(equipment information rice money species series fish sheep))
end

这个文件把不同的变形规则用正则表达进行匹配并替换得到变形后的复数形式,当然文件还包括不可数和不规则变化的单词表。

在实际开发过程中,我们也可能遇到变形后不满足我们要求的情况,例如:我们要求一个单词foo变形后还是foo,但通过默认的变形规则foo变形为foos,不满足我们的要求。

$ ruby script/console
>> "foo".pluralize
=> "foos"

如果想要得到希望的变形结果(foo->foo),可以把这个单词增加到不可数单词列表中,增加如下内容到environment.rb文件结尾:

config/environment.rb:
...
 
Inflector.inflections do |inflect|
  inflect.uncountable "foo"
end

重新启动交互环境(script/console),再次运行复数(pluralize)命令,可以得到想要的结果。

 

$ ruby script/console
>> "foo".pluralize
=> "foo"

另外,可以将变形规则用块(block)的方式批量传递到Inflector.inflections中,例如:

Inflector.inflections do |inflect|
  inflect.plural /^(ox)$/i, '/1/2en'
  inflect.singular /^(ox)en/i, '/1'
 
  inflect.irregular 'octopus', 'octopi'
 
  inflect.uncountable "equipment"
end
如果文件inflections.rb中存在相同的变形规则,上面的方法将覆盖inflections.rb中存在的变形规则。