views:

375

answers:

2

Hello,

Given the associations defined below, I'm hoping someone can shed some light on why I can't access all the Classifieds, that belong to a Category, that in turn belongs to a Section. I'm guessing it has something to do with the fact that there's a polymorphic relationship in there, but I'd like to know if there is a proper way to do what I want using just association statements, or if I have to "roll my own" and get the Classifieds in two-phases.

Probably easier to understand by just seeing the code:

class CategorySection < ActiveRecord::Base
  has_many :categories
  has_many :categorizations, :through => :categories
  has_many :classifieds, :through => :categories
end

class Category < ActiveRecord::Base
  belongs_to :section, :class_name => 'CategorySection', 
                       :foreign_key => 'category_section_id', 
                       :counter_cache => true
  has_many :categorizations
  has_many :classifieds, :through => :categorizations, 
                         :source => :categorizable, 
                         :source_type => 'Classified'
end

class Categorization < ActiveRecord::Base
  belongs_to :category, :counter_cache => true
  belongs_to :categorizable, :polymorphic => true
end

class Classified < ActiveRecord::Base
  has_one :categorization, :as => :categorizable, :dependent => :destroy
  has_one :category, :through => :categorization
end

For the most part, this is all working properly except for one association I can't figure out. Given a CategorySection, how can I quickly find out all the Classifieds that belong to it?

For example:

Given a Category, I can get all it's categorizations:

>> @category.categorizations
>> [<Categorization...>,<Categorization...>]

Given a Category, I can get all the classifieds in it:

>> @category.classifieds
>> [<Classified...>,<Classified...>]

Given a Section, I can get all of its categories:

>> @section.categories
>> [<Category...>,<Category...>]

Given a Section, I can get all of its categorizations going through :categories

>> @section.categorizations
>> [<Categorization...>,<Categorization...>]

But, given a Section, I cannot get all of its classifieds going through :categories

>> @section.classifieds
ActiveRecord::HasManyThroughSourceAssociationMacroError: 
Invalid source reflection macro :has_many :through for 
has_many :classifieds, :through => :categories. Use :source 
to specify the source reflection.

I've taking the error message's advice of specifying a :source, but I still can't get it to work. I've tried pretty much every combination of options on that association that I can think of but to no avail.

Any advice or suggestions would be most appreciated. Thanks in advance.

Sincerely, Kenny

A: 

Have you tried defining the has_many without ":through"?

class CategorySection < ActiveRecord::Base
  has_many :categories
  has_many :categorizations, :through => :categories
  has_many :classifieds
end

Might want to take a look at this railscast.

eggdrop
Sadly that won't work since there's no foreign_key back to a CategorySection in a Classified. You could go the other way, a Classified can figure out which Category it's in, then get it's CategorySection, but not the way I'm looking for.
Kenny C
Is there a reason you can't have a foreign key back to a CategorySection in a Classified?
eggdrop
Nope, no stiff requirement that I can't do that, it just means I have to set the section foreign key manually in a before_save filter. That might be the solution to this problem, and if it is, then fine, but I was originally curious if there was a way to solve this using just association declarations. Manually setting foreign keys is not normally the "Rails Way" of doing things so I was interested in a more "correct" solution and normalized solution. FWIW....
Kenny C
A: 

As I remember Rails don't allow to use :through more than once in associations. For sure you can't do something like this:

has_many :books
has_many :authors, :through => :books
has_many :phones, :through => :authors

but I'm not sure if it allow to do double :through in seperate models (like yours). Firstly you can try to do it without polymorphism - if it works, then my suggestion is wrong.

I think that Rails is trying to generete single SQL query for all your associations chain - and it's quite complicated.

For sure you can write your own :finder_sql for that association.

klew