Note that there are some explanatory texts on larger screens.

plurals
  1. POCan't get an STI/ActiveRecord model to do what I expect
    primarykey
    data
    text
    <p>I'm trying to build a simple survey/questionnaire app. Surveys have <code>Questions</code>; most questions consist of a single content field (the question itself), for which the survey taker will write in a free-text response. (There are also a couple of other fields not relevant to this discussion.) However, users can also create <code>MultipleChoiceQuestions</code> or <code>LikertQuestions</code> (e.g., answers on a 1 - 5 scale). (In the case of <code>MultipleChoiceQuestions</code>, there will be another model called <code>Answer</code> such that a <code>MultipleChoiceQuestion</code> has_many <code>Answers</code>). Here are my design choices, so far as I know:</p> <p>1) Inherit from Question:</p> <pre><code>class Question &lt; ActiveRecord::Base attr_accessible :id, :content end class MultipleChoiceQuestion &lt; Question attr_accessible :type end class LikertQuestion &lt; Question attr_accessible :type, :min, :max, :label_min, label_max end </code></pre> <p>2) Use a module/mixin with the shared attributes and methods:</p> <pre><code>module Question @content, @id def method1 end end class MultipleChoiceQuestion &lt; ActiveRecord::Base include Question end class LikertQuestion &lt; ActiveRecord::Base include Question attr_accessible :type, :min, :max, :label_min, label_max end </code></pre> <p>This seems a clear-cut case of inheritance, so I went with option 1. Since then, I can't get it to work. Single Table Inheritance seemed simple enough, so I gave <code>MultipleChoiceQuestion</code> and <code>LikertQuestion</code> each <code>type:string</code> in their schema. Here are the schema for each (from db/schema.rb):</p> <pre><code> create_table "questions", :force =&gt; true do |t| t.integer "parent" t.string "type" t.string "content" t.datetime "created_at", :null =&gt; false t.datetime "updated_at", :null =&gt; false t.integer "survey_id" end create_table "multiple_choice_questions", :force =&gt; true do |t| t.datetime "created_at", :null =&gt; false t.datetime "updated_at", :null =&gt; false t.string "type" end create_table "likert_questions", :force =&gt; true do |t| t.integer "min" t.integer "max" t.string "label_min" t.string "label_max" t.datetime "created_at", :null =&gt; false t.datetime "updated_at", :null =&gt; false t.string "type" end </code></pre> <p>If I implement option 1, above, then MultipleChoiceQuestion and LikertQuestion somehow do not actually include any of their unique fields as specified in schema.rb; instead, they have only the inherited fields from Question. See console output:</p> <pre><code>1.9.3p392 :001 &gt; Question =&gt; Question(id: integer, parent: integer, content: string, created_at: datetime, updated_at: datetime, survey_id: integer) 1.9.3p392 :002 &gt; LikertQuestion =&gt; LikertQuestion(id: integer, parent: integer, content: string, created_at: datetime, updated_at: datetime, survey_id: integer) 1.9.3p392 :003 &gt; MultipleChoiceQuestion =&gt; MultipleChoiceQuestion(id: integer, parent: integer, content: string, created_at: datetime, updated_at: datetime, survey_id: integer) 1.9.3p392 :004 &gt; LikertQuestion.new(:min =&gt; 3) ActiveRecord::UnknownAttributeError: unknown attribute: min </code></pre> <p>Somebody on StackOverflow said that Question should be an abstract class. But if I add <code>self.abstract_class = true</code> to Question.rb, then I get the following:</p> <pre><code>1.9.3p392 :001 &gt; Question =&gt; Question(abstract) 1.9.3p392 :002 &gt; LikertQuestion =&gt; LikertQuestion(id: integer, min: integer, max: integer, label_min: string, label_mid: string, label_max: string, created_at: datetime, updated_at: datetime, type: string) 1.9.3p392 :003 &gt; MultipleChoiceQuestion =&gt; MultipleChoiceQuestion(id: integer, created_at: datetime, updated_at: datetime, type: string) 1.9.3p392 :004 &gt; LikertQuestion.new(:content =&gt; "foo") ActiveRecord::UnknownAttributeError: unknown attribute: content </code></pre> <p><code>LikertQuestion</code> and <code>MultipleChoiceQuestion</code> show <em>only</em> their unique fields and do not inherit fields from the parent.</p> <p>1) What am I missing here? Regardless of whether inheritance is the optimal solution, I must be overlooking something obvious.</p> <p>2) Should I be using the module approach instead of inheritance? As I mentioned, inheritance seemed like a no-brainer: <code>LikertQuestion</code> and <code>MultipleChoiceQuestion</code> really are kinds of <code>Questions</code>. If I use the module approach, I lose the ability to say things like <code>survey.questions()</code>, <code>survey.questions.build()</code>, and presumably other handy stuff. What do Rails hotshots do in this situation? I'll do whatever that is.</p> <p>No posts on StackOverflow offer a very comprehensive discussion of the pros and cons of subclassing vs. mixin.</p> <p>Using Ruby 1.9.3 (though thinking of switching to 2.0), Rails 3.2.3.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload