I have a case of polymorphic association and STI here.
# app/models/car.rb
class Car < ActiveRecord::Base
belongs_to :borrowable, :polymorphic => tru
Just had this issue in Rails 4.2
. I found two ways to resolve:
--
The problem is that Rails uses the base_class
name of the STI relationship.
The reason for this has been documented in the other answers, but the gist is that the core team seem to feel that you should be able to reference the table rather than the class for a polymorphic STI association.
I disagree with this idea, but am not part of the Rails Core team, so don't have much input into resolving it.
There are two ways to fix it:
--
class Association < ActiveRecord::Base
belongs_to :associatiable, polymorphic: true
belongs_to :associated, polymorphic: true
before_validation :set_type
def set_type
self.associated_type = associated.class.name
end
end
This will change the {x}_type
record before the creation of the data into the db. This works very well, and still retains the polymorphic nature of the association.
ActiveRecord
methods#app/config/initializers/sti_base.rb
require "active_record"
require "active_record_extension"
ActiveRecord::Base.store_base_sti_class = false
#lib/active_record_extension.rb
module ActiveRecordExtension #-> http://stackoverflow.com/questions/2328984/rails-extending-activerecordbase
extend ActiveSupport::Concern
included do
class_attribute :store_base_sti_class
self.store_base_sti_class = true
end
end
# include the extension
ActiveRecord::Base.send(:include, ActiveRecordExtension)
####
module AddPolymorphic
extend ActiveSupport::Concern
included do #-> http://stackoverflow.com/questions/28214874/overriding-methods-in-an-activesupportconcern-module-which-are-defined-by-a-cl
define_method :replace_keys do |record=nil|
super(record)
owner[reflection.foreign_type] = ActiveRecord::Base.store_base_sti_class ? record.class.base_class.name : record.class.name
end
end
end
ActiveRecord::Associations::BelongsToPolymorphicAssociation.send(:include, AddPolymorphic)
A more systemic way to fix the issue is to edit the ActiveRecord
core methods which govern it. I used references in this gem to find out which elements needed to be fixed / overridden.
This is untested and still needs extensions for some of the other parts of the ActiveRecord core methods, but seems to work for my local system.