rails :through

one-to-one

class Employee < ActiveRecord::Base
  has_one :office
end
class Office < ActiveRecord::Base
  belongs_to :employee    # foreign key - employee_id
end
注意规则: 哪个模型有belongs_to,哪个模型有外键

one-to-many

class Manager < ActiveRecord::Base
  has_many :employees
end
class Employee < ActiveRecord::Base
  belongs_to :manager     # foreign key - manager_id
end
规则同上,关联model里有belongs_to

many-to-many

有两种方法构建多对多

第一种方式通过 has_many 用一个 :through选项和一个连接模块(join model)来实现,需要两步走

class Assignment < ActiveRecord::Base
  belongs_to :programmer  # foreign key - programmer_id
  belongs_to :project     # foreign key - project_id
end
class Programmer < ActiveRecord::Base
  has_many :assignments
  has_many :projects, :through => :assignments
end
class Project < ActiveRecord::Base
  has_many :assignments
  has_many :programmers, :through => :assignments
end
第二种方式通过在model里直接写has_and_belongs_to_many来构建

class Programmer < ActiveRecord::Base
  has_and_belongs_to_many :projects       # foreign keys in the join table
end
class Project < ActiveRecord::Base
  has_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::Base
  has_many :authorships
  has_many :books, :through => :authorships
end

class Authorship < ActiveRecord::Base
  belongs_to :author
  belongs_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::Base
  has_many   :clients
  has_many   :invoices, :through => :clients
end

class Client < ActiveRecord::Base
  belongs_to :firm
  has_many   :invoices
end

class Invoice < ActiveRecord::Base
  belongs_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::Base
  has_many   :users
  has_many   :avatars, :through => :users
end

class User < ActiveRecord::Base
  belongs_to :group
  has_one    :avatar
end

class Avatar < ActiveRecord::Base
  belongs_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::Base
  belongs_to :post
  belongs_to :tag, :inverse_of => :taggings
end

:inverse_of

关于:inverse_of,有一个很有意思的例子,如下:

class Man < ActiveRecord::Base
  has_one :face, :inverse_of => :man
end

class Face < ActiveRecord::Base
  belongs_to :man, :inverse_of => :face
end

m = Man.first
f = m.face
如果没有:inverse_of,那么m和f.man将是同一对象的两个不同实例,f.man将从数据库再取出一个man对象,如果加了:inverse_of,那么这两个将是同一个了。

你可以在 has_one, has_many and belongs_to中使用它。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值