My question is essentially the same as this one: Polymorphic Association with multiple associations on the same model
However, the proposed/accepted solution does no
None of these solutions seem to work on Rails 5. For some reason, it looks like the behaviour around the association conditions has changed. When assigning the related object, the conditions don't seem to be used in the insert; only when reading the association.
My solution was to override the setter method for the association:
has_one :photo, -> { photo_type: 'primary_photo'},
as: 'attachable',
dependent: :destroy
def photo=(photo)
photo.photo_type = 'primary_photo'
super
end
None of the previous answers helped me solve this problem, so I'll put this here incase anyone else runs into this. Using Rails 4.2 +.
Create the migration (assuming you have an Addresses table already):
class AddPolymorphicColumnsToAddress < ActiveRecord::Migration
def change
add_column :addresses, :addressable_type, :string, index: true
add_column :addresses, :addressable_id, :integer, index: true
add_column :addresses, :addressable_scope, :string, index: true
end
end
Setup your polymorphic association:
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end
Setup the class where the association will be called from:
class Order < ActiveRecord::Base
has_one :bill_address, -> { where(addressable_scope: :bill_address) }, as: :addressable, class_name: "Address", dependent: :destroy
accepts_nested_attributes_for :bill_address, allow_destroy: true
has_one :ship_address, -> { where(addressable_scope: :ship_address) }, as: :addressable, class_name: "Address", dependent: :destroy
accepts_nested_attributes_for :ship_address, allow_destroy: true
end
The trick is that you have to call the build method on the Order
instance or the scope
column won't be populated.
So this does NOT work:
address = {attr1: "value"... etc...}
order = Order.new(bill_address: address)
order.save!
However, this DOES WORK.
address = {attr1: "value"... etc...}
order = Order.new
order.build_bill_address(address)
order.save!
Hope that helps someone else.
Can you add a SecondaryPhoto model like:
class SecondaryPhoto < Photo
end
and then skip the :class_name from the has_one :secondary_photo?
In Rails 5 you have to define attr_accessor for :attachable_id and specify for relation :class_name and :foreign_key options only. You will get ...AND attachable_type = 'SecondaryPhoto' if as: :attachable used
class Post
attr_accessor :attachable_id
has_one :photo, :as => :attachable, :dependent => :destroy
has_one :secondary_photo, -> { where attachable_type: 'SecondaryPhoto' }, class_name: "Photo", dependent: :destroy, foreign_key: :attachable_id
Rails 4.2+
class Photo
belongs_to :attachable, :polymorphic => true
end
class Post
has_one :photo, :as => :attachable, :dependent => :destroy
has_one :secondary_photo, -> { where attachable_type: "SecondaryPhoto"},
class_name: Photo, foreign_key: :attachable_id,
foreign_type: :attachable_type, dependent: :destroy
end
You need to provide foreign_key according ....able'ness or Rails will ask for post_id column in photo table. Attachable_type column will fills with Rails magic as SecondaryPhoto