has_many :through with class_name and foreign_key

I know this is an old question, but I just spent some time running into the same errors and finally figured it out. This is what I did:

class User < ActiveRecord::Base
  has_many :listing_managers
  has_many :managed_listings, through: :listing_managers, source: :listing
end

class Listing < ActiveRecord::Base
  has_many :listing_managers
  has_many :managers, through: :listing_managers, source: :user
end

class ListingManager < ActiveRecord::Base
  belongs_to :listing
  belongs_to :user
end

This is what the ListingManager join table looks like:

create_table :listing_managers do |t|
  t.integer :listing_id
  t.integer :user_id
end

Hope this helps future searchers.


The issue here is that in

has_many :managers, through: :listing_managers

ActiveRecord can infer that the name of the association on the join model (:listing_managers) because it has the same name as the has_many :through association you're defining. That is, both listings and listing_mangers have many managers.

But that's not the case in your other association. There, a listing_manager has_many :listings, but a user has_many :managed_listings. So ActiveRecord is unable to infer the name of the association on ListingManager that it should use.

This is what the :source option is for (see http://guides.rubyonrails.org/association_basics.html#has-many-association-reference). So the correct declaration would be:

has_many :managed_listings, through: :listing_managers, source: :listing

(p.s. you don't actually need the :foreign_key or :class_name options on the other has_many :through. You'd use those to define direct associations, and then all you need on a has_many :through is to point to the correct association on the :through model.)


i had several issues with my models, had to add the foreign key as well as the source and class name... this was the only workaround i found:

  has_many :ticket_purchase_details, foreign_key: :ticket_purchase_id, source: :ticket_purchase_details, class_name: 'TicketPurchaseDetail'

  has_many :details, through: :ticket_purchase_details, source: :ticket_purchase, class_name: 'TicketPurchaseDetail'