0

I have a set up where I have multiple models inheriting from a Base model - standard Single Table Inheritance:

class Parent < ActiveRecord::Base
end

class A < Parent
end

class B < Parent
end

My STI setup is correct and works great! However, I want to add :type specific attributes such as description.

For example, I want all A types of Parent to have the description, "I am the A type of Parent. My function is for..."

I want to avoid replicating data over and over (having each instance of A store the same description for example).

The first thing that came to mind for this was to have a model specific method on the Subclass. So something like:

class A < Parent

  def self.description
    "I am the A type of Parent. My function is for..."
  end

end

I don't like this solution because this really is data on the specific type of subclass (rather than on the subclass instance itself) and you get all the problems that come with making this behavior (deployments to change data, etc.)

Is this the only way to do it or are there alternatives I just am not seeing?

2 Answers2

0

What about creating a model for the description?

class Description < ActiveRecord::Base
  has_many :as
end

class A < Parent
  belongs_to :description

  before_save { description_id = 1 }
end

This way, you manage the content of description in the database and can modify it through either a web interface or migrations. Furthermore, you can easily add different descriptions for the different subclasses, or even change them per instance if that is ever required.

One downside of this approach is that you need to create the model with the correct description. One potential solution could be the before_save or before_create hook, but I'm sure those are not the only way to do it.

jdno
  • 4,104
  • 1
  • 22
  • 27
  • That's a fantastic approach that addresses my concerns. I believe it necessary to also have the before_save function more dynamic (not have a hardcoded value for id) but the idea is the same! Thank you very much. Gonna keep the question open to solicit more potential ideas but you've solved it for sure. – Lewaa Bahmad Jul 27 '17 at 12:32
  • @LewaaBahmad Glad to hear that. Please take the code as food for thought and not an actual implementation. Hardcoding `id` feels very icky. :D – jdno Jul 27 '17 at 13:16
  • Oh absolutely. You've presented the concept in a very distilled fashion though which I appreciate. I'll share my implementation with you when I spike on it. – Lewaa Bahmad Jul 28 '17 at 01:04
0

for your case I prefer to use ruby Duck typing as follow

class ParentAll
  def talk(object1)
    object1.talk
  end
end

class A < ParentAll
  def talk
    puts 'I am the A type of Parent. My function is for...'
  end
end

class B < ParentAll
  def talk
    puts 'I am the B type of Parent. My function is for...'
  end
end

@parent = ParentAll.new
puts 'Using the A'
@parent.talk(A.new)
  # this will output talk from A

puts 'Using the B'
@parent.talk(B.new)
  # this will output talk from B
widjajayd
  • 6,090
  • 4
  • 30
  • 41
  • Yeah, that was my first impulse. However, this would mean that to update data, I would have to update the method and therefore the subclass - which I do not want to do. The talking behavior should be independent of the content of the message and I should be able to update the message without re-deploying the application. Thank you though! – Lewaa Bahmad Jul 27 '17 at 12:21