Store child class's name in database column in polymorphic association - rails

穿精又带淫゛_ 提交于 2019-12-10 11:29:21

问题


I have a class, say, Car from which I have inherited classes Black and Red as follows:

class Car::Black < Car
end

class Car::Red < Car
end

Now, there is another class, say, CarPurchase which has many Cars of both varieties. The associations are as follows:

# In Black and Red models:
has_many :car_purchases, as: :purchasable, dependent:destroy

# In CarPurchase model:
belongs_to :purchasable, polymorphic: true

Now I'm trying to save the CarPurchases like this:

black_car.car_purchases.new()   # black_car is an object of class Car::Black

My database has a column called purchasable_type. The problem is that records are saved with purchasable_type 'Car' and not 'Car::Black'. I tried saving the purchasable_type explicitly also while creating record. No luck. Help please.


回答1:


You could do something like this:

class Car < ActiveRecord::Base
  self.abstract_class = true
  class Black < Car; end
  class Red < Car; end
end

The reason it stores Car is defined in ActiveRecord::Associations::BelongsToPolymorphicAssociation#replace_keys Excerpt:

def replace_keys(record)
  super
  owner[reflection.foreign_type] = record.class.base_class.name
end

and ActiveRecord::Inheritance::ClassMethods::base_class Excerpt:

def base_class
  unless self < Base
    raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
  end

  if superclass == Base || superclass.abstract_class?
    self
  else
    superclass.base_class
  end
end

So if Car is an abstract_class then it will store Car::Black other wise the base_class will resolve to Car. Making Car an abstract_class will not lose most of the magic e.g. Car::Black still knows it's table_name.

Caveat using Car as an abstract_class means it cannot be instantiated directly.

For Example:

class Car < ActiveRecord::Base
  class Black < Car
  end
end 
Car::Black.base_class.name 
#=> Car
Car::Black.table_name
#=> "cars"
Car.new 
#New Car record
class Car < ActiveRecord::Base
  self.abstract_class = true
end
Car::Black.base_class.name 
#=> Car::Black 
Car::Black.table_name
#=> "cars"
Car.new
#=> NotImplementedError: Car is an abstract class and cannot be instantiated.


来源:https://stackoverflow.com/questions/45140335/store-child-classs-name-in-database-column-in-polymorphic-association-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!