(本翻译纯粹为了学习,切勿用于商业目的,转载请指明出处:http://blog.csdn.net/fuliangliang)
Rails Cookbook翻译(四)
处方3.4 使用Active Record为你的数据库建立模型
问题:
你已经有了一个关系数据库,你想使用Active Record来创建一个模型来表示它。(我们将使用3.1部分的cookbook_dev数据库)
解决方案:
首先,创建一个叫做cookbook的Rails工程:
$ rails cookbook
在cookbook应用程序的根目录下,使用model生成器为cookbook_dev数据库中的每一个表创建了模型的脚手架(scaffolding)(除了连接表外):
~/cookbook$ ruby script/generate model chapter
create app/models/
exists test/unit/
exists test/fixtures/
create app/models/chapter.rb
identical test/unit/chapter_test.rb
identical test/fixtures/chapters.yml
~/cookbook$ ruby script/generate model recipe
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/recipe.rb
identical test/unit/recipe_test.rb
identical test/fixtures/recipes.yml
~/cookbook$ ruby script/generate model tag
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/tag.rb
identical test/unit/tag_test.rb
identical test/fixtures/tags.yml
接下来,在app/models目录下的文件里添加一下声名:
~/cookbook/app/models/chapter.rb:
class Chapter < ActiveRecord::Base
has_many :recipes
ene
~/cookbook/app/models/recipe.rb:
class Recipe < ActiveRecord::Base
belong_to :chapter
has_and_belongs_to_many :tags
end
~/cookbook/app/models/tag.rb:
class Tag < ActiveRecord::Base
has_and_belongs_to_many :recipes
end
讨论:
Active Record在我们cookbook数据库的上一层创建了一个ORM层。这个层允许Rails通过Active Record类定义的面向对象的接口来和数据库通信。在这个映射中,类代表数据库中的表,而对象则代表表中的行。
我们的数据库包含了一对多和多对多的关系。我们需要提供给Active Record一些信息来说明他们之间是什么关系。我们通过使用Active Record类定义的每一个模型中声明这种关系。
对于chaptes和recipes之间的一对多的关系,我们在chapter.rb中添加了has_many :recipes,在recipe.rb中添加了belongs_to :chapter。注意这些声明就像使用英语那样描述关系(例如,“Chapter have many recipes.”)。通过使用类似真实语言的方式,帮助我们使复杂的数据模型概念化。
这个在recipes和tags之间的多对多的关系仍需要Active Record声明的帮助。我们已经在recipes.rb里添加了has_and_belongs_to_many :tags,在tags.rb里添加了has_and_belongs_to_many :recipes。充当媒介的reicpes_tags连接表的没有一点踪迹。这是被设计好了的。Active Record在背后来处理和维护多对多关系的复杂性,提供访问数据的一个符合直觉得接口。
你可以通过使用Rails控制台来验证这些模式的存在以及它们之间的关系。在你应用程序的根目录运行脚本script/console,让你进入了irb会话,通过它可以访问你的Rails环境。(-s选项告诉控制台当你退出时回滚所有对数据库的改变。)
~/cookbook/test$ ruby script/console –s
Loading development environment in sandbox.
Any modifications you make will be rolled back on exit.
首先创建一个chapter对象:
>> c = Chapter.new
=> #<Chapter:0x8e158f4 @new_record=true, @attributes={"sort_order"=>0,
"title"=>nil}>
接着创建Recipe对象:
>> r = Recipe.new
=> #<Recipe:0x8e131d0 @new_record=true, @attributes={"see_also"=>nil,
"discussion"=>nil, "sort_order"=>0, "title"=>nil, "chapter_id"=>nil,
"solution"=>nil, "problem"=>nil}>
现在,把recipe添加到chapter里:
>> c.recipes << r
=> [#<Recipe:0x8e131d0 @new_record=true, @attributes={"see_also"=>nil,
"discussion"=>nil, "sort_order"=>0, "title"=>nil, "chapter_id"=>nil,
"solution"=>nil, "problem"=>nil}>]
观察一下Chapter对象,显示我们已经成添加了我们的recipe对象了。
>> c
=> #<Chapter:0x8e158f4 @new_record=true, @recipes=[#<Recipe:0x8e131d0
@new_record=true, @attributes={"see_also"=>nil, "discussion"=>nil,
"sort_order"=>0, "title"=>nil, "chapter_id"=>nil, "solution"=>nil,
"problem"=>nil}>], @attributes={"sort_order"=>0, "title"=>nil}>
现在我们可以通过章节中的recipes数组来访问chapter中的每一个recipes了.
>> c.recipes
=> [#<Recipe:0x8e131d0 @new_record=true, @attributes={"see_also"=>nil,
"discussion"=>nil, "sort_order"=>0, "title"=>nil, "chapter_id"=>nil,
"solution"=>nil, "problem"=>nil}>]
记住你可以一直通过调用methods方法来查看一个对象的所拥有方法。
>> c.methods
我们创建了一个Tag对象并且添加到Recipe对象中,来演示recipes到tags的关系。
>> t = Tag.new
=> #<Tag:0x8e09e3c @new_record=true, @attributes={"name"=>nil}>
>> r.tags << t
=> [#<Tag:0x8e09e3c @new_record=true, @attributes={"name"=>nil}>]
Finally, inspection confirms that the Tag was added to our Recipe object:
>> r.tags
=> [#<Tag:0x8e09e3c @new_record=true, @attributes={"name"=>nil}>]