Skip to content

Commit

Permalink
Replace Subclasses with Strategies: Step Thirteen
Browse files Browse the repository at this point in the history
* Always instantiate the same root class
  • Loading branch information
jferris committed Feb 7, 2013
1 parent a3b36db commit 19ee304
Show file tree
Hide file tree
Showing 18 changed files with 68 additions and 36 deletions.
4 changes: 2 additions & 2 deletions example_app/app/controllers/questions_controller.rb
Expand Up @@ -31,13 +31,13 @@ def update
private

def build_question
@question = type.constantize.new(question_params)
@question = Question.new(question_params)
@question.build_submittable(type, submittable_params)
@question.survey = @survey
end

def type
params[:question][:type]
params[:question][:submittable_type]
end

def question_params
Expand Down
4 changes: 2 additions & 2 deletions example_app/app/controllers/types_controller.rb
Expand Up @@ -2,7 +2,7 @@ class TypesController < ApplicationController
def new
@question = Question.find(params[:question_id])
assign_type
@new_question = type.constantize.new
@new_question = Question.new
@new_question.build_submittable(type, {})
end

Expand Down Expand Up @@ -37,6 +37,6 @@ def submittable_attributes
end

def type
params[:question][:type]
params[:question][:submittable_type]
end
end
10 changes: 7 additions & 3 deletions example_app/app/models/question.rb
@@ -1,10 +1,14 @@
class Question < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection

QUESTION_TYPES = %w(OpenQuestion MultipleChoiceQuestion ScaleQuestion).freeze
QUESTION_TYPES = %w(
OpenSubmittable
MultipleChoiceSubmittable
ScaleSubmittable
).freeze

validates :submittable, associated: true
validates :type, presence: true, inclusion: QUESTION_TYPES
validates :submittable_type, presence: true, inclusion: QUESTION_TYPES
validates :title, presence: true

belongs_to :submittable, polymorphic: true
Expand Down Expand Up @@ -33,7 +37,7 @@ def summarize(summarizer)
def switch_to(type, new_attributes, submittable_attributes)
attributes = self.attributes.merge(new_attributes)
cloned_attributes = attributes.except('id', 'type', 'submittable_type')
new_question = type.constantize.new(cloned_attributes)
new_question = Question.new(cloned_attributes)
new_question.build_submittable(type, submittable_attributes)
new_question.id = id

Expand Down
@@ -1,5 +1,5 @@
<ol>
<% submittable.options.each do |option| -%>
<% multiple_choice_submittable.options.each do |option| -%>
<li>
<%= submission_fields.radio_button :text, option.text, id: dom_id(option) %>
<%= content_tag :label, option.text, for: dom_id(option) %>
Expand Down
4 changes: 2 additions & 2 deletions example_app/app/views/questions/_form.html.erb
@@ -1,8 +1,8 @@
<%= simple_form_for question, as: :question, url: url do |form| -%>
<%= form.hidden_field :type %>
<%= form.hidden_field :submittable_type %>
<%= form.input :title %>
<%= render(
"#{question.to_partial_path}_form",
"#{question.submittable.to_partial_path}_form",
submittable: question.submittable,
form: form
) %>
Expand Down
12 changes: 9 additions & 3 deletions example_app/app/views/questions/edit.html.erb
Expand Up @@ -5,20 +5,26 @@

<%= link_to(
'Scale Question',
new_question_type_path(@question, question: { type: 'ScaleQuestion' })
new_question_type_path(
@question,
question: { submittable_type: 'ScaleSubmittable' }
)
) %>
<%= link_to(
'Multiple Choice Question',
new_question_type_path(
@question,
question: { type: 'MultipleChoiceQuestion' }
question: { submittable_type: 'MultipleChoiceSubmittable' }
)
) %>
<%= link_to(
'Open Question',
new_question_type_path(@question, question: { type: 'OpenQuestion' })
new_question_type_path(
@question,
question: { submittable_type: 'OpenSubmittable' }
)
) %>
</p>

Expand Down
@@ -1,5 +1,5 @@
<ol>
<% submittable.steps.each do |step| -%>
<% scale_submittable.steps.each do |step| -%>
<li>
<%= submission_fields.radio_button :text, step %>
<%= submission_fields.label "text_#{step}", label: step %>
Expand Down
20 changes: 14 additions & 6 deletions example_app/app/views/surveys/show.html.erb
Expand Up @@ -6,17 +6,26 @@
<%= link_to(
'Add Multiple Choice Question',
new_survey_question_path(@survey, question: { type: 'MultipleChoiceQuestion' })
new_survey_question_path(
@survey,
question: { submittable_type: 'MultipleChoiceSubmittable' }
)
) %>
<%= link_to(
'Add Open Question',
new_survey_question_path(@survey, question: { type: 'OpenQuestion' })
new_survey_question_path(
@survey,
question: { submittable_type: 'OpenSubmittable' }
)
) %>
<%= link_to(
'Add Scale Question',
new_survey_question_path(@survey, question: { type: 'ScaleQuestion' })
new_survey_question_path(
@survey,
question: { submittable_type: 'ScaleSubmittable' }
)
) %>
<%= simple_form_for [@survey, @completion] do |form| -%>
Expand All @@ -26,9 +35,8 @@
<%= form.fields_for "answers_attributes[#{question.id}]", Answer.new do |submission_fields| -%>
<%= submission_fields.label :text, label: question.title %>
<%= render(
question,
submission_fields: submission_fields,
submittable: question.submittable
question.submittable,
submission_fields: submission_fields
) %>
<%= link_to 'Edit', edit_question_path(question) %>
<% end -%>
Expand Down
2 changes: 1 addition & 1 deletion example_app/app/views/types/new.html.erb
Expand Up @@ -4,7 +4,7 @@
url: question_types_path(@question)
) do |form| -%>
<%= form.hidden_field :type %>
<%= form.hidden_field :submittable_type %>
<%= render(
"#{@new_type}s/#{@new_type}_form",
question: @new_question,
Expand Down
16 changes: 16 additions & 0 deletions example_app/db/migrate/20130207214017_remove_questions_type.rb
@@ -0,0 +1,16 @@
class RemoveQuestionsType < ActiveRecord::Migration
def up
remove_column :questions, :type
end

def down
add_column :questions, :type, :string

connection.update(<<-SQL)
UPDATE questions
SET type = REPLACE(submittable_type, 'Submittable', 'Question')
SQL

change_column_null :questions, :type, true
end
end
3 changes: 1 addition & 2 deletions example_app/db/schema.rb
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.

ActiveRecord::Schema.define(:version => 20130207164259) do
ActiveRecord::Schema.define(:version => 20130207214017) do

create_table "answers", :force => true do |t|
t.integer "completion_id", :null => false
Expand Down Expand Up @@ -68,7 +68,6 @@

create_table "questions", :force => true do |t|
t.string "title", :null => false
t.string "type", :null => false
t.integer "survey_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
Expand Down
11 changes: 6 additions & 5 deletions example_app/spec/factories/application.rb
Expand Up @@ -29,19 +29,20 @@
text 'Hello'
end

factory :question, class: 'OpenQuestion' do
survey
factory :question do
sequence(:title) { |n| "Question #{n}" }
submittable factory: :open_submittable
survey

factory :multiple_choice_question, class: 'MultipleChoiceQuestion' do
factory :multiple_choice_question do
submittable factory: :multiple_choice_submittable
end

factory :open_question, class: 'OpenQuestion' do
factory :open_question do
submittable factory: :open_submittable
end

factory :scale_question, class: 'ScaleQuestion' do
factory :scale_question do
submittable factory: :scale_submittable
end
end
Expand Down
8 changes: 3 additions & 5 deletions example_app/spec/models/question_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'

describe Question do
it { should validate_presence_of :type }
it { should validate_presence_of :submittable_type }

Question::QUESTION_TYPES.each do |type|
it { should allow_value(type).for(:type) }
it { should allow_value(type).for(:submittable_type) }
end

it { should_not allow_value('Other').for(:type) }
it { should_not allow_value('Other').for(:submittable_type) }

it { should validate_presence_of :title }

Expand Down Expand Up @@ -71,7 +71,6 @@
{ minimum: 1, maximum: 2 })

new_question.errors.should be_empty
new_question.should be_a(ScaleQuestion)
submittable = new_question.submittable
submittable.should be_a(ScaleSubmittable)
submittable.minimum.should eq 1
Expand All @@ -85,7 +84,6 @@
new_question = question.switch_to('ScaleQuestion', {}, { minimum: 1 })

new_question.errors.should be_present
new_question.should be_a(ScaleQuestion)
new_question.submittable.should be_a(ScaleSubmittable)
new_question.submittable.minimum.should eq 1
end
Expand Down
6 changes: 3 additions & 3 deletions example_app/spec/support/features/survey_taker.rb
Expand Up @@ -23,10 +23,10 @@ def start

def answer(question_title, answer_text)
question = Question.find_by_title!(question_title)
case question
when OpenQuestion
case question.submittable
when OpenSubmittable
fill_in question_title, with: answer_text
when ScaleQuestion, MultipleChoiceQuestion
when ScaleSubmittable, MultipleChoiceSubmittable
within %{li:contains("#{question_title}")} do
choose answer_text
end
Expand Down

0 comments on commit 19ee304

Please sign in to comment.