Permalink
Browse files

Hide summary for unanswered questions

* Allow users to skip questions
* Hide summary for questions the user hasn't answered yet
* Introduces smell Divergent Change
* Staging for refactoring Extract Decorator
  • Loading branch information...
jferris committed Feb 20, 2013
1 parent d456557 commit d60656aafb50601fc8c2fd25143d152257a246aa
@@ -1,7 +1,7 @@
class SummariesController < ApplicationController
def show
@survey = Survey.find(params[:survey_id])
@summaries = @survey.summaries_using(summarizer)
@summaries = @survey.summaries_using(summarizer, constraints)
end

private
@@ -13,4 +13,16 @@ def summarizer
def summarizer_class
"Summarizer::#{params[:id].classify}".constantize
end

def constraints
if include_unanswered?
{}
else
{ answered_by: current_user }
end
end

def include_unanswered?
params[:unanswered]
end
end
@@ -4,8 +4,6 @@ class Answer < ActiveRecord::Base
belongs_to :completion
belongs_to :question

validates :text, presence: true

def self.for_user(user)
joins(:completion).where(completions: { user_id: user.id }).last_or_null
end
@@ -20,6 +20,14 @@ class Question < ActiveRecord::Base
delegate :breakdown, :score, to: :submittable
delegate :title, to: :survey, prefix: true

def answered_by?(user)
answers.
joins(:completion).
where(completions: { user_id: user }).
where("answers.text <> ''").
exists?
end

def most_recent_answer_text
answers.most_recent.text
end
@@ -1,4 +1,6 @@
class Survey < ActiveRecord::Base
NO_ANSWER = "You haven't answered this question".freeze

include ActiveModel::ForbiddenAttributesProtection

validates_presence_of :title
@@ -7,9 +9,13 @@ class Survey < ActiveRecord::Base
has_many :completions
has_many :questions

def summaries_using(summarizer)
def summaries_using(summarizer, options = {})
questions.map do |question|
question.summary_using(summarizer)
if !options[:answered_by] || question.answered_by?(options[:answered_by])
question.summary_using(summarizer)
else
Summary.new(question.title, NO_ANSWER)
end
end
end
end
@@ -1,5 +1,7 @@
<%= render 'nav', survey: @survey %>

<%= link_to "Show questions I haven't answered", unanswered: true %>

<ol class="summary">
<%= render partial: 'summaries/summary', collection: @summaries %>
</ol>
@@ -34,6 +34,28 @@
summary_for_question('Name?').should eq('Billy')
end

scenario 'only view questions which you have answered' do
maker = SurveyMaker.new
maker.open_question 'Name?'
maker.open_question 'Favorite color?'
survey = maker.survey
taker = SurveyTaker.new(survey)
sign_in
taker.complete 'Brian', ''
as_another_user { taker.complete 'Billy', 'Red' }

view_summary survey, 'Most Recent'

summary_for_question('Name?').should eq('Billy')
summary_for_question('Favorite color?').
should eq("You haven't answered this question")

show_unanswered_questions

summary_for_question('Favorite color?').
should eq('Red')
end

scenario 'view your answers' do
maker = SurveyMaker.new
maker.open_question 'Name?'
@@ -57,10 +79,15 @@
as_another_user { taker.complete 'Billy' }

view_summary survey, 'Your Answers'
show_unanswered_questions

summary_for_question('Name?').should eq('No response')
end

def show_unanswered_questions
click_on "Show questions I haven't answered"
end

def view_summary(survey, type)
visit survey_path(survey)
click_link type
@@ -3,8 +3,6 @@
describe Answer do
it { should belong_to(:completion) }
it { should belong_to(:question) }

it { should validate_presence_of(:text) }
end

describe Answer, '.for_user' do
@@ -16,6 +16,30 @@
it { should have_many(:answers) }
end

describe Question, '#answered_by?' do
it 'returns true for a user with an answer' do
user = create(:user)
question = create(:question)
AnswerCreator.new(question.survey, user: user).answer(question)

question.should be_answered_by(user)
end

it 'returns false for a user without an answer' do
user = create(:user)
other_user = create(:user)
survey = create(:survey)
question = create(:question, survey: survey)
other_question = create(:question, survey: survey)
creator = AnswerCreator.new(survey, user: user)
creator.answer(question, '')
creator.answer(other_question, 'hello')
AnswerCreator.new(survey, user: other_user).answer(question)

question.should_not be_answered_by(user)
end
end

describe Question, '#build_submittable' do
it 'builds a submittable with the given type and attributes' do
expected_value = 1.day.ago
@@ -11,7 +11,7 @@
it 'applies the given summarizer to each question' do
questions = [build_stubbed(:question), build_stubbed(:question)]
survey = build_stubbed(:survey, questions: questions)
summarizer = stub('summarizer', summarize: 'result')
summarizer = stub_summarizer

result = survey.summaries_using(summarizer)

@@ -20,6 +20,36 @@
result.map(&:value).should == %w(result result)
end

it 'applies the given summarizer to each question answered by the user' do
user = build_stubbed(:user)
answered_question = stub_question(user: user, answered: true)
unanswered_question = stub_question(user: user, answered: false)
questions = [answered_question, unanswered_question]
questions.stubs(:answered_by).with(user).returns(questions)
survey = build_stubbed(:survey, questions: questions)
summarizer = stub_summarizer

result = survey.summaries_using(summarizer, answered_by: user)

should_summarize_questions [answered_question], summarizer
result.map(&:title).should eq questions.map(&:title)
result.map(&:value).
should eq ['result', "You haven't answered this question"]
end

def stub_question(arguments)
build_stubbed(:question).tap do |question|
question.
stubs(:answered_by?).
with(arguments[:user]).
returns(arguments[:answered])
end
end

def stub_summarizer
stub('summarizer', summarize: 'result')
end

def should_summarize_questions(questions, summarizer)
questions.each do |question|
summarizer.should have_received(:summarize).with(question)
@@ -6,7 +6,7 @@ def initialize(survey, options = {})
@completion = create(:completion, options.merge(survey: @survey))
end

def answer(question, answer_text)
def answer(question, answer_text = 'hello')
create(
:answer,
question: question,

0 comments on commit d60656a

Please sign in to comment.