开发者

Advanced associations in rails

Right now I'm using a has_and_belongs_to_many association for two of my models like so:

class Books < ActiveRecord::Base
    has_and_belongs_to_many :publishers
end

class Publisher < ActiveRecord::Base
    belongs_to :publishing_company
    has_and_belongs_to_many :books
end
开发者_运维问答

You'll notice that each publisher belongs to a publishing company:

class PublishingCompany < ActiveRecord::Base
    has_many :publishers
end

My goal is to set up an association that would allow me to do:

PublishingCompany.find(1).books

Is this possible with conventional RoR associations?


The concept you're looking for is specifying a second degree association using the :through parameter on a has_many association on your PublishingCompany class. Doing second degree associations (that will join 2 extra tables) are very common, I don't think I've ever performed a third degree association though (publishers -> publisher_books -> books), and if I recall right Rails gets fairly sloppy at understanding what you're trying to do once you push associations this far.

The first option that's worth trying is:

class PublishingCompany
  has_many :publishers
  has_many :books, :through => :publishers
end

The Rails documentation however states that a :through parameter can only be used on a has_many or belongs_to, meaning this shouldn't work through the has_and_belongs_to_many association you have.

Your second options is what I had to do on an early system I wrote on Rails 1. I'll likely get voted down for this, but it was something I had to cook up since I couldn't get rails to handle it.

Since you're only going to use the association in a read only fashion, I just created a fake method to handle it. Be warned, this is a last resort. As a side note I personally dislike has_and_belongs_to_many associations as I find it strange that you don't have objects that you can manipulate that represent the rows of the join table.

class Books
  has_many :book_publishers
  has_many :publishers, :through => :book_publishers
end

class BookPublisher
  belongs_to :book
  belongs_to :publisher
end

class Publisher
  has_many :book_publishers  
  has_many :books, :through => :book_publishers
  belongs_to :publishing_company
end

class PublishingCompany
  has_many :publishers
  has_many :book_publishers, :through => :publishers

  def books
    book_publishers.map{|bp|bp.book}
  end
end

# typical use, eager loading to avoid N+1
company = PublishingCompany.first :include => {:book_publishers => :book}
company.books.each {|b| puts b.title}


This should work for you.

class PublishingCompany < ActiveRecord::Base
  has_many :books, :through => :publishers, :source => :books
end

:source parameter is the one you need to use

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜