one-to-one
class Employee < ActiveRecord::Basehas_one :office
end
class Office < ActiveRecord::Basebelongs_to :employee # foreign key - employee_id
end
注意规则:
哪个模型有belongs_to,哪个模型有外键
one-to-many
class Manager < ActiveRecord::Basehas_many :employees
end
class Employee < ActiveRecord::Basebelongs_to :manager # foreign key - manager_id
end
规则同上,关联model里有belongs_to
many-to-many
有两种方法构建多对多
第一种方式通过 has_many 用一个 :through选项和一个连接模块(join model)来实现,需要两步走
class Assignment < ActiveRecord::Basebelongs_to :programmer # foreign key - programmer_idbelongs_to :project # foreign key - project_id
end
class Programmer < ActiveRecord::Basehas_many :assignmentshas_many :projects, :through => :assignments
end
class Project < ActiveRecord::Basehas_many :assignmentshas_many :programmers, :through => :assignments
end
第二种方式通过在model里直接写has_and_belongs_to_many来构建
class Programmer < ActiveRecord::Basehas_and_belongs_to_many :projects # foreign keys in the join table
end
class Project < ActiveRecord::Basehas_and_belongs_to_many :programmers # foreign keys in the join table
end
(译者注:active record规定,连接表名称由两个目标表名按字母顺序连接组成 连接符采用下划线)
(译者注:说白了就是要么自己创建一个中间表,里面自己可以再添加东西,要么让active record给你创建一个中间表,但是你自己无法操作)
决定到底使用那一种方法有时让人头疼,但如何你需要把中间表作为一个实体来处理,那么请用:through,如何你确定不需要会用到中间表,你可以用has_and_belongs_to_many
apidock上:through深入讲解
has_many能用:through选项来定位中间关联表以检索信息,这个操作与has_and_belongs_to_many很像,优点是你能在里面增加验证,callback和添加一些属性
class Author < ActiveRecord::Basehas_many :authorshipshas_many :books, :through => :authorships endclass Authorship < ActiveRecord::Basebelongs_to :authorbelongs_to :book end@author = Author.first @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to @author.books # selects all books by using the Authorship join model让我们往中间表中加一个has_many
class Firm < ActiveRecord::Basehas_many :clientshas_many :invoices, :through => :clients endclass Client < ActiveRecord::Basebelongs_to :firmhas_many :invoices endclass Invoice < ActiveRecord::Basebelongs_to :client end@firm = Firm.first @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm @firm.invoices # selects all invoices by going through the Client join model你也能在中间表中加入has_one
class Group < ActiveRecord::Basehas_many :usershas_many :avatars, :through => :users endclass User < ActiveRecord::Basebelongs_to :grouphas_one :avatar endclass Avatar < ActiveRecord::Basebelongs_to :user end@group = Group.first @group.users.collect { |u| u.avatar }.flatten # select all avatars for all users in the group @group.avatars # selects all avatars by going through the User join model.特别需要注意的是中间表中的has_many和has_one,都是只读的
@group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around @group.avatars.delete(@group.avatars.last) # so would this如果你在中间表中用了belongs_to,那么你可以在belongs_to里加入:inverse_of选项,这意味着下面这句可以正常工作了(tags有一个has_many:through的连接)
@post = Post.first @tag = @post.tags.build :name => "ruby" @tag.save如果:inverse_of被设置,那么最后一行会被保存
class Taggable < ActiveRecord::Basebelongs_to :postbelongs_to :tag, :inverse_of => :taggings end
:inverse_of
关于:inverse_of,有一个很有意思的例子,如下:
class Man < ActiveRecord::Basehas_one :face, :inverse_of => :man endclass Face < ActiveRecord::Basebelongs_to :man, :inverse_of => :face endm = Man.first f = m.face如果没有:inverse_of,那么m和f.man将是同一对象的两个不同实例,f.man将从数据库再取出一个man对象,如果加了:inverse_of,那么这两个将是同一个了。
你可以在 has_one, has_many and belongs_to中使用它。