Rails Polymorphic Association with multiple associations on the same model?

I have done that in my project The trick is that photos need a column that will be used in has_one condition to distinguish between primary and secondary photos. Pay attention to what happens in :conditions here has_one :photo, :as => 'attachable', :conditions => {:photo_type => 'primary_photo'}, :dependent => :destroy has_one :secondary_photo, :class_name => 'Photo', :as => 'attachable', :conditions => {:photo_type => 'secondary_photo'}, :dependent => :destroy The beauty of this approach is that when you create photos using post. Build_photo the photo_type will automatically be pre-populated with corresponding type, like 'primary_photo'.

ActiveRecord is smart enough to do that.

I have done that in my project. The trick is that photos need a column that will be used in has_one condition to distinguish between primary and secondary photos. Pay attention to what happens in :conditions here.

Has_one :photo, :as => 'attachable', :conditions => {:photo_type => 'primary_photo'}, :dependent => :destroy has_one :secondary_photo, :class_name => 'Photo', :as => 'attachable', :conditions => {:photo_type => 'secondary_photo'}, :dependent => :destroy The beauty of this approach is that when you create photos using @post. Build_photo, the photo_type will automatically be pre-populated with corresponding type, like 'primary_photo'. ActiveRecord is smart enough to do that.

I like the idea a lot, only problem is I can't get rails to write the correct value into the photo_type column, it's always Photo. Am I missing something, how do you get rails to write 'primary photo' into the photo_type column? – opsb Jul 13 '10 at 21:39 1 What's the name of your column?

Make sure it's not just type since that's a special column rails uses to write the name of current class. – hakunin Jul 14 '10 at 0:54 2 The above code didn't work for me. The :conditions => {:photo_type => 'primary_photo'} didn't change the photo_type column content.It was still the class of my model.

What did work was add a new column to the database, photo_sub_type (string), and set my :conditions => {:photo_sub_type => 'primary_photo'} but then every association has to have the :conditions => {:photo_sub_type => some value here} specified. But it works just as I wanted it to. Use the same Photo model to attach many different types of photos to another model.

– Rob Sutherland Jan 20 at 15:09 The above code works, BUT: The reason you're having problems, Rob, is that the above code assumes you are doing Single Table Inheritance in your model – Houen Sep 17 at 16:46 1 @Houen Look carefully. In both associations :class_name is Photo (implicitly for :photo, explicitly for :secondary_photo). The only thing you need is to have a photo_type column on photos table.

This column will not make photos STI, you would need a type column for that. The only reason you need it is that by using has_one you can't distinguish associations based on order, so you have to use some other indication. Photo_type is there for that purpose only, to help has_one distinguish between 2 otherwise indistinguishable rows in the photos table.

– hakunin Sep 17 at 19:13.

I didn't use it, but I googled around and looked into Rails sources and I think that what you're looking for is :foreign_type. Try it and tell if it works :) has_one :secondary_photo, :as => :attachable, :class_name => "Photo", :dependent => :destroy, :foreign_type => 'SecondaryPost' I think that type in your question should be Post instead of Photo and, respectively, it would be better to use SecondaryPost as it assigned to Post model. EDIT: Above answer is completly wrong.

:foreign_type is availble in polymorphic model in belongs_to association to specify name of the column that contains type of associated model. As I look in Rails sources, this line sets this type for association: dependent_conditions {:photo_type => 0} and :conditions => {:photo_type => 1}, respectively. I know it is not a solution you are looking for, but I can't find anything better.By the way, maybe it would be better to just use has_many association?

Unfortunately Rails 2.1 doesn't have foreign_type – Matt Rogish Mar 22 '10 at 21:00 I think it was added around 2.3. So I think that there is no other way of doing what you want. You can try adding this feature manualy or, what is much better, upgrade your application to 2.3.5 and always stay on latest version. – klew Mar 22 '10 at 21:09 I tried w/Rails 2.3.5 and it still tells me unknown key: foreign_type :( – Matt Rogish Mar 23 '10 at 16:20 Take a look at associations.

Rb valid_keys_for_has_one_association :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key – Matt Rogish Mar 23 '10 at 16:29.

That does seem like a workable solution - I was hoping there was a "built-in" way to do what I wanted.... – Matt Rogish Mar 22 '10 at 20:21 I tried that - it passes Photo as the type just as if I did class_name! – Matt Rogish Mar 22 '10 at 20:31 How are you "attaching" the secondary photo to the Post? In any case, I'm curious to know if klew's answer about :foreign_type works.

– Rob Biedenharn Mar 22 '10 at 20:58.

Your going to have to monkey patch the notion of foreign_type into has_one relationship. This is what I did for has_many. In a new .

Rb file in your initializers folder I called mine add_foreign_type_support. Rb It lets you specify what your attachable_type is to be. Example: has_many photo, :class_name => "Picture", :as => attachable, :foreign_type => 'Pic' module ActiveRecord module Associations class HasManyAssociation Options:finder_sql @finder_sql = interpolate_sql(@reflection.

Options:finder_sql) when @reflection. Options:as resource_type = @reflection. Options:foreign_type.

To_s. Camelize || @owner.class. Base_class.name.

To_s @finder_sql = "#{@reflection. Quoted_table_name}. #{@reflection.

Options:as}_id = #{owner_quoted_id} AND " @finder_sql += "#{@reflection. Quoted_table_name}. #{@reflection.

Options:as}_type = #{@owner.class. Quote_value(resource_type)}" else @finder_sql += ")" end @finder_sql Quoted_table_name}. #{@reflection.

Primary_key_name} = #{owner_quoted_id}" @finder_sql Options:counter_sql @counter_sql = interpolate_sql(@reflection. Options:counter_sql) elsif @reflection. Options:finder_sql # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ @reflection.

Options:counter_sql = @reflection. Options:finder_sql. Sub(/SELECT (\/\*.

*? \*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } @counter_sql = interpolate_sql(@reflection. Options:counter_sql) else @counter_sql = @finder_sql end end end end end # Add foreign_type to options list module ActiveRecord module Associations # :nodoc: module ClassMethods private mattr_accessor :valid_keys_for_has_many_association @@valid_keys_for_has_many_association = :class_name, :table_name, :foreign_key, :primary_key, :dependent, :select, :conditions, :include, :order, :group, :having, :limit, :offset, :as, :foreign_type, :through, :source, :source_type, :uniq, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, :validate, :inverse_of end end.

Ain't working when corrected syntax errors – sharas Jul 17 '10 at 16:01 This is the code I'm using with my rails 2.3.8 application. I would say step threw the logic and see if you have to make adjustments. The idea is your pass a foreign_type options params and if that exists you overload the default behavor on the select statement you might have to to_s.

Camelize the value if you pass it in as a :symbol – simonslaw Jul 22 '10 at 17:09.

I didn't use it, but I googled around and looked into Rails sources and I think that what you're looking for is :foreign_type. I think that type in your question should be Post instead of Photo and, respectively, it would be better to use SecondaryPost as it assigned to Post model. Above answer is completly wrong.

:foreign_type is availble in polymorphic model in belongs_to association to specify name of the column that contains type of associated model. As you can see it uses base_class. Name to get type name.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions