Search code examples
ruby-on-railsruby-on-rails-4activerecordsti

How do I create a new model, related to an existing model, using STI?


If I have the following models, which use STI:

# Organization Model
class Organization < ActiveRecord::Base
  has_many :questions
  has_many :answers, :through => :questions
end

# Base Question Model
class Question < ActiveRecord::Base
  belongs_to :organization
  has_many :answers
end

# Subclass of Question
class TextQuestion < Question

end

# Subclass of Question
class CheckboxQuestion < Question

end

What is the correct way to build a new object that is a particular type of Question and also relates to Organization? Or in other words, if I have an organization, and I want that organization to have a new CheckboxQuestion, can I use the regular builder methods?

For example, I was expecting to be able to do:

org = Organization.last
org.text_questions.build(:question_text => "What is your name?")

... but this gives me an NoMethodError: undefined method text_questions error.


Solution

  • The Organization model is not aware of the classes that inherit from the Question so you can initiate/create question instances in this way. In order to initiate/create questions of specific type, you have to explicitly set it yourself. For example:

    organization = Organization.where(...).last
    organization.questions.build(question_text: 'text', type: 'TextQuestion')
    

    You could define multiple has_many *_questions at the Organization class, but it feels like a bad design and things will get out of hand if you end up having a lot of Question subclasses in your application.