sheki
sheki

Reputation: 9349

How to get polymorphic relations with inheritance working in rails?

I have the following rails models.

class Service < ApplicationRecord
  self.table_name ='service'
end

class ChildA < Service
  has_many :charges
end

class ChildB < Service
  self.table_name = "childb_table"
  has_many :charges
end

class Charges < ApplicationRecord
  :belongs_to chargeable, polymorphic: true
end
# code using this
a = ClassB.new.save
charge = Charges.new.save
a.charges.add(a) # this adds the column with the class name 'Service'

I try to save the objects but the chargeable_type field is always set as the base class service and the never the child class.

How do I get around this?

Upvotes: 2

Views: 1979

Answers (2)

Mayur Patel
Mayur Patel

Reputation: 789

You can define your Service class as an abstract.

Tested with Rails 5.1

class Service < ApplicationRecord
  self.table_name ='service'
  self.abstract_class = true
end

Example from: http://www.rubydoc.info/docs/rails/4.0.0/ActiveRecord%2FInheritance%2FClassMethods%3Aabstract_class

class SuperClass < ActiveRecord::Base
  self.abstract_class = true
end

class Child < SuperClass
  self.table_name = 'the_table_i_really_want'
end

Upvotes: 3

ReggieB
ReggieB

Reputation: 8212

I think the solution is in the rails documentation:

Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts and member posts that use the posts table for STI. In this case, there must be a type column in the posts table.

Note: The attachable_type= method is being called when assigning an attachable. The class_name of the attachable is passed as a String.

class Asset < ActiveRecord::Base
  belongs_to :attachable, polymorphic: true

  def attachable_type=(class_name)
     super(class_name.constantize.base_class.to_s)
  end
end

class Post < ActiveRecord::Base
  # because we store "Post" in attachable_type now dependent: :destroy will work
  has_many :assets, as: :attachable, dependent: :destroy
end

class GuestPost < Post
end

class MemberPost < Post
end

Upvotes: 2

Related Questions