A Guide to Active Record Associations
To learn more about the different types of associations, read the next section of this guide. That’s followed by some tips and tricks for working with associations, and then by a complete reference to the methods and options for associations in Rails.
2 The Types of Associations
In Rails, an association is a connection between two Active Record models. Associations are implemented using macro-style calls, so that you can declaratively add features to your models.
For example, by declaring that one model belongs_to another, you instruct Rails to maintain Primary Key–Foreign Key information between instances of the two models, and you also get a number of utility methods added to your model.
2.3 The has_many Association
一对多的关系
A has_many association indicates a one-to-many connection with another model. You’ll often find this association on the “other side” of a belongs_to association. This association indicates that each instance of the model has zero or more instances of another model.
2.4 The has_many :through Association
多对多的关系,一般通过第三个model,也就是中介model(join models)来实现多多映射。 这其实也是through的含义了。
class
Physician < ActiveRecord::Base
has_many
:appointments
has_many
:patients
,
:through
=>
:appointments
end
class
Appointment < ActiveRecord::Base
belongs_to
:physician
belongs_to
:patient
end
class
Patient < ActiveRecord::Base
has_many
:appointments
has_many
:physicians
,
:through
=>
:appointments
end
2.7 区别 belongs_to and has_one
If you want to set up a 1–1 relationship between two models, you’ll need to add belongs_to to one, and has_one to the other. How do you know which is which?
字面上理解是,belongs_to是关联关系,所属关系;而has_one是包含关系。
The distinction is in where you place the foreign key (it goes on the table for the class declaring the belongs_to association), but you should give some thought to the actual meaning of the data as well. The has_one relationship says that one of something is yours – that is, that something points back to you.
2.8 区别 has_many :through and has_and_belongs_to_many
这两种都能实现多对多的关系。
(1)Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use has_and_belongs_to_many , which allows you to make the association directly.
(2)The second way to declare a many-to-many relationship is to use has_many :through . This makes the association indirectly, through a join model.
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database).
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.
2.9 Polymorphic Associations
A slightly more advanced twist on associations is the polymorphic association . With polymorphic associations, a model can belong to more than one other model, on a single association.
You can think of a polymorphic belongs_to declaration as setting up an interface that any other model can use.
这个部分非常有意义~~
2.10 Self Joins
In designing a data model, you will sometimes find a model that should have a relation to itself. For example, you may want to store all employees in a single database model, but be able to trace relationships such as between manager and subordinates. This situation can be modeled with self-joining associations:
class Employee < ActiveRecord::Base
has_many :subordinates, :class_name => "Employee",
:foreign_key => "manager_id"
belongs_to :manager, :class_name => "Employee"
end
总结一下:
(1) has_***都是在被关联的(associated)table中创建外键,此外键映射到含有声明model所对应表。
比如下面的例子,外键是在accounts表,映射到suppliers表
class Supplier < ActiveRecord::Base
has_one :account
end
(2)belongs_**是在声明model对应的table中创建一个外键
比如下面的例子,外键是在orders表,映射到customers表
class Order < ActiveRecord::Base
belongs_to :customer
end
(3)belongs_to和has_many 经常成对出现。以下例而言
class Comment < ActiveRecord::Base
belongs_to :post
end
class Post < ActiveRecord::Base
validates :name, :presence => true
validates :title, :presence => true,
:length => { :minimum => 5 }
has_many :comments
end
belongs_to建立关系:Each comment belongs to one post;
has_many建立关系: One post can have many comments;
数据关系:if you have an instance variable @post containing a post, you can retrieve all the comments belonging to that post as the array @post.comments .
3 Tips, Tricks, and Warnings
3.1 Controlling Caching
3.2 Avoiding Name Collisions
You are not free to use just any name for your associations. Because creating an association adds a method with that name to the model, it is a bad idea to give an association a name that is already used for an instance method of ActiveRecord::Base . The association method would override the base method and break things. For instance, attributes or connection are bad names for associations.
3.3 Updating the Schema
这个部分是需要手动编码的部分。
Associations are extremely useful, but they are not magic. You are responsible for maintaining your database schema to match your associations. In practice, this means two things, depending on what sort of associations you are creating.
(1) For belongs_to associations you need to create foreign keys, and
(2) for has_and_belongs_to_many associations you need to create the appropriate join table.
If you create a has_and_belongs_to_many association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the :join_table option, Active Record creates the name by using the lexical order of the class names. So a join between customer and order models will give the default join table name of “customers_orders” because “c” outranks “o” in lexical ordering.
We pass :id => false to create_table because that table does not represent a model. That’s required for the association to work properly . If you observe any strange behaviour in a has_and_belongs_to_many association like mangled models IDs, or exceptions about conflicting IDs, chances are you forgot that bit.
3.4 Controlling Association Scope
By default, associations look for objects only within the current module’s scope. This can be important when you declare Active Record models within a module.
To associate a model with a model in a different namespace, you must specify the complete class name in your association declaration:
4. Detailed Association Reference
4.1 belongs_to Association Reference
The belongs_to association creates a one-to-one match with another model.
If the associated object has already been retrieved from the database for this object, the cached version will be returned. To override this behavior (and force a database read), pass true as the force_reload argument.
Cached 提供的作用,在开发或者测试阶段,经常会有很大的问题。
4.5 Association Callbacks
Association callbacks are similar to normal callbacks, but they are triggered by events in the life cycle of a collection. There are four available association callbacks:
4.6 Association Extensions
You’re not limited to the functionality that Rails automatically builds into association proxy objects. You can also extend these objects through anonymous modules, adding new finders, creators, or other methods.
一个典型的关系建立的步骤,
(1)生成一个需要被关联的Model:$ rails generate model Comment commenter:string body:text post:references
这样就得到如下关联模型,
class Comment < ActiveRecord::Base
belongs_to :post
end
以及db migration文件,此文件包含有关联信息 t.references :post;The t.references line sets up a foreign key column for the association between the two models.
(2)更改数据库,运行命令$ rake db:migrate
(3)You’ll need to edit the post.rb file to add the other side of the association: 添加
class Post < ActiveRecord::Base
validates :name, :presence => true
validates :title, :presence => true,
:length => { :minimum => 5 }
has_many :comments
end
(4)为新增加的被关联的model,添加路由信息:Adding a Route for Comments
(5)生成与被关联对象相关的控制器:Generating a Controller:$ rails generate controller Comments
注意,这一步会生成 控制器和视图。
(6)编辑相关的控制器和视图,实现被关联模型 的数据显示和url跳转链接。
如果(1)的不是通过reference生成,那相关的外键则需要手动添加。 而对于 has_and_belongs_to_many,又需要手动添加关系表。具体参考3.3。
更简单的说明:
(1)$ rails generate scaffold student given_name:string middle_name:string family_name:string birthday:date grade_point_average:decimal start_date:date
(2)$ rails generate scaffold award award_name:string description:string year:integer student_id:integer
(3)$ rake db:migrate
(4)award.rb & student.rb,添加关系声明belongs_to & has_many
如此看:关系声明是在数据迁移之后的,那关系什么如何作用到数据库层面呢?。这里要注意了,所以model的逻辑本身都不是数据库层面的,比如model中的校验,这个校验是model自身的,是model层面的,而不是数据库这个level的。理解了这点,就能理解关系声明的scope了。