Permalink
Browse files

Replace Subclasses with Strategies: Step Ten

* Move state for first strategy out of root class
  • Loading branch information...
jferris committed Feb 7, 2013
1 parent ecc8e7b commit 41b49f49706135572a1b907f6a4c9747fb8446bb
@@ -32,7 +32,7 @@ def update

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

@@ -43,6 +43,14 @@ def type
def question_params
params.
require(:question).
permit(:title, :options_attributes, :minimum, :maximum)
permit(:title, :options_attributes)
end

def submittable_params
if submittable_attributes = params[:question][:submittable_attributes]
submittable_attributes.permit(:minimum, :maximum)
else
{}
end
end
end
@@ -3,11 +3,16 @@ def new
@question = Question.find(params[:question_id])
assign_type
@new_question = type.constantize.new
@new_question.build_submittable({})
end

def create
@question = Question.find(params[:question_id])
@new_question = @question.switch_to(type, params[:question], {})
@new_question = @question.switch_to(
type,
question_params,
submittable_attributes
)

if @new_question.errors.empty?
redirect_to @question.survey
@@ -23,6 +28,14 @@ def assign_type
@new_type = type.underscore
end

def question_params
params[:question].except(:submittable_attributes)
end

def submittable_attributes
params[:question][:submittable_attributes] || {}
end

def type
params[:question][:type]
end
@@ -3,13 +3,16 @@ class Question < ActiveRecord::Base

QUESTION_TYPES = %w(OpenQuestion MultipleChoiceQuestion ScaleQuestion).freeze

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

belongs_to :submittable, polymorphic: true
belongs_to :survey
has_many :answers

accepts_nested_attributes_for :submittable

delegate :breakdown, :score, to: :submittable
delegate :title, to: :survey, prefix: true

@@ -1,4 +1,2 @@
class ScaleQuestion < Question
validates :maximum, presence: true
validates :minimum, presence: true
end
@@ -1,6 +1,9 @@
class ScaleSubmittable < ActiveRecord::Base
has_one :question, as: :submittable

validates :maximum, presence: true
validates :minimum, presence: true

def breakdown
sprintf('Average: %.02f', answers.average('text'))
end
@@ -10,7 +13,7 @@ def score(text)
end

def steps
(question.minimum..question.maximum).to_a
(minimum..maximum).to_a
end

private
@@ -1,2 +1,4 @@
<%= form.input :minimum %>
<%= form.input :maximum %>
<%= form.fields_for :submittable do |submittable_fields| -%>
<%= submittable_fields.input :minimum %>
<%= submittable_fields.input :maximum %>
<% end -%>
@@ -0,0 +1,50 @@
class MoveScaleQuestionStateToScaleSubmittable < ActiveRecord::Migration
def up
add_column :scale_submittables, :minimum, :integer
add_column :scale_submittables, :maximum, :integer

connection.insert(<<-SQL)
INSERT INTO scale_submittables
(id, created_at, updated_at, minimum, maximum)
SELECT
id, created_at, updated_at, minimum, maximum
FROM questions
WHERE questions.type = 'ScaleQuestion'
SQL

connection.update(<<-SQL)
UPDATE questions
SET submittable_id = id, submittable_type = 'ScaleSubmittable'
WHERE type = 'ScaleQuestion'
SQL

remove_column :questions, :minimum
remove_column :questions, :maximum
end

def down
add_column :questions, :maximum, :integer
add_column :questions, :minimum, :integer

connection.update(<<-SQL)
UPDATE questions
SET
minimum = (
SELECT minimum
FROM scale_submittables
WHERE questions.submittable_id = scale_submittables.id
),
maximum = (
SELECT maximum
FROM scale_submittables
WHERE questions.submittable_id = scale_submittables.id
)
WHERE questions.submittable_type = 'ScaleSubmittable'
SQL

connection.delete('DELETE FROM scale_submittables')

remove_column :scale_submittables, :maximum
remove_column :scale_submittables, :minimum
end
end
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.

ActiveRecord::Schema.define(:version => 20130131205918) do
ActiveRecord::Schema.define(:version => 20130131211856) do

create_table "answers", :force => true do |t|
t.integer "completion_id", :null => false
@@ -72,15 +72,15 @@
t.integer "survey_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "minimum"
t.integer "maximum"
t.integer "submittable_id"
t.string "submittable_type"
end

create_table "scale_submittables", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "minimum"
t.integer "maximum"
end

create_table "surveys", :force => true do |t|
@@ -43,14 +43,13 @@
end

factory :scale_question, class: 'ScaleQuestion' do
minimum 1
maximum 2

submittable factory: :scale_submittable
end
end

factory :scale_submittable do
minimum 1
maximum 2
end

factory :survey do
@@ -3,10 +3,11 @@
feature 'user answers scale question' do
scenario 'with valid answer' do
sign_in
view_survey_with_question :scale,
title: 'How many fingers do you have?',
minimum: 0,
maximum: 10
view_survey_with_question(
:scale,
{ title: 'How many fingers do you have?' },
{ minimum: 0, maximum: 10 }
)
choose '10'
submit_answers
answer_to_question('How many fingers do you have?').
@@ -25,13 +25,14 @@
end

scenario 'with valid open question' do
question = create(:scale_question)
submittable = create(:scale_submittable)
question = create(:scale_question, submittable: submittable)
edit_question question

change_type 'Open Question' do
end

page.should_not have_step(question.minimum)
page.should_not have_step(submittable.minimum)
end

scenario 'with invalid question' do
@@ -44,7 +44,12 @@
completion = create(:completion, survey: survey)
scores = [1, 2, 3]
scores.each do |score|
question = create(:scale_question, survey: survey, minimum: 1, maximum: 3)
submittable = create(:scale_submittable, minimum: 1, maximum: 3)
question = create(
:scale_question,
survey: survey,
submittable: submittable
)
create(:answer, completion: completion, question: question, text: score)
end

@@ -64,30 +64,29 @@
describe Question, '#switch_to' do
it 'changes the question type and deletes the old question when valid' do
question = create(:open_question)
expected_value = 1.day.ago

new_question = question.switch_to(
'ScaleQuestion',
{ minimum: 1, maximum: 2 },
{ created_at: expected_value })
{},
{ minimum: 1, maximum: 2 })

new_question.errors.should be_empty
new_question.should be_a(ScaleQuestion)
new_question.submittable.should be_a(ScaleSubmittable)
new_question.submittable.created_at.should eq expected_value
new_question.minimum.should eq 1
new_question.maximum.should eq 2
submittable = new_question.submittable
submittable.should be_a(ScaleSubmittable)
submittable.minimum.should eq 1
submittable.maximum.should eq 2
Question.count.should eq 1
end

it 'leaves the question alone when the new attributes are invalid' do
question = create(:open_question)

new_question = question.switch_to('ScaleQuestion', { minimum: 1 }, {})
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.minimum.should eq 1
new_question.submittable.minimum.should eq 1
end
end

This file was deleted.

Oops, something went wrong.
@@ -1,12 +1,15 @@
describe ScaleSubmittable do
it { should have_one(:question) }

it { should validate_presence_of(:maximum) }
it { should validate_presence_of(:minimum) }
end

describe ScaleSubmittable, '#breakdown' do
it 'returns the average' do
survey = create(:survey)
question = create(:scale_question, minimum: 0, maximum: 10, survey: survey)
submittable = ScaleSubmittable.new(question: question)
submittable = ScaleSubmittable.new(minimum: 0, maximum: 10)
question = create(:scale_question, survey: survey, submittable: submittable)
taker = AnswerCreator.new(survey)
taker.answer question, 6
taker.answer question, 6
@@ -29,8 +32,7 @@

describe ScaleSubmittable, '#steps' do
it 'returns all numbers starting at the minimum and ending at the maximum' do
question = build_stubbed(:scale_question, minimum: 2, maximum: 5)
submittable = ScaleSubmittable.new(question: question)
submittable = ScaleSubmittable.new(minimum: 2, maximum: 5)
submittable.steps.should eq [2, 3, 4, 5]
end
end
@@ -9,9 +9,13 @@ def view_editable_survey
view_survey survey
end

def view_survey_with_question(type, attributes = {})
def view_survey_with_question(type, question_attrs = {}, submittable_attrs = {})
survey = create(:survey)
question = create(:"#{type}_question", attributes.merge(survey: survey))
submittable = create(:"#{type}_submittable", submittable_attrs)
question = create(
:"#{type}_question",
question_attrs.merge(survey: survey, submittable: submittable)
)
view_survey survey
end

@@ -27,12 +27,16 @@ def scored_multiple_choice_question(title, texts_and_scores)
end

def scale_question(title, range)
submittable = create(
:scale_submittable,
minimum: range.first,
maximum: range.last
)
create(
:scale_question,
title: title,
minimum: range.first,
maximum: range.last,
survey: survey
submittable: submittable,
survey: survey,
title: title
)
end

0 comments on commit 41b49f4

Please sign in to comment.