当前位置: 代码迷 >> 综合 >> rails :through
  详细解决方案

rails :through

热度:8   发布时间:2023-12-06 18:00:15.0

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中使用它。


  相关解决方案