Skip to content

Commit d60656a

Browse files
committed
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
1 parent d456557 commit d60656a

File tree

10 files changed

+114
-9
lines changed

10 files changed

+114
-9
lines changed

example_app/app/controllers/summaries_controller.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class SummariesController < ApplicationController
22
def show
33
@survey = Survey.find(params[:survey_id])
4-
@summaries = @survey.summaries_using(summarizer)
4+
@summaries = @survey.summaries_using(summarizer, constraints)
55
end
66

77
private
@@ -13,4 +13,16 @@ def summarizer
1313
def summarizer_class
1414
"Summarizer::#{params[:id].classify}".constantize
1515
end
16+
17+
def constraints
18+
if include_unanswered?
19+
{}
20+
else
21+
{ answered_by: current_user }
22+
end
23+
end
24+
25+
def include_unanswered?
26+
params[:unanswered]
27+
end
1628
end

example_app/app/models/answer.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ class Answer < ActiveRecord::Base
44
belongs_to :completion
55
belongs_to :question
66

7-
validates :text, presence: true
8-
97
def self.for_user(user)
108
joins(:completion).where(completions: { user_id: user.id }).last_or_null
119
end

example_app/app/models/question.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ class Question < ActiveRecord::Base
2020
delegate :breakdown, :score, to: :submittable
2121
delegate :title, to: :survey, prefix: true
2222

23+
def answered_by?(user)
24+
answers.
25+
joins(:completion).
26+
where(completions: { user_id: user }).
27+
where("answers.text <> ''").
28+
exists?
29+
end
30+
2331
def most_recent_answer_text
2432
answers.most_recent.text
2533
end

example_app/app/models/survey.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class Survey < ActiveRecord::Base
2+
NO_ANSWER = "You haven't answered this question".freeze
3+
24
include ActiveModel::ForbiddenAttributesProtection
35

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

10-
def summaries_using(summarizer)
12+
def summaries_using(summarizer, options = {})
1113
questions.map do |question|
12-
question.summary_using(summarizer)
14+
if !options[:answered_by] || question.answered_by?(options[:answered_by])
15+
question.summary_using(summarizer)
16+
else
17+
Summary.new(question.title, NO_ANSWER)
18+
end
1319
end
1420
end
1521
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<%= render 'nav', survey: @survey %>
22

3+
<%= link_to "Show questions I haven't answered", unanswered: true %>
4+
35
<ol class="summary">
46
<%= render partial: 'summaries/summary', collection: @summaries %>
57
</ol>

example_app/spec/features/user_views_survey_summary_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@
3434
summary_for_question('Name?').should eq('Billy')
3535
end
3636

37+
scenario 'only view questions which you have answered' do
38+
maker = SurveyMaker.new
39+
maker.open_question 'Name?'
40+
maker.open_question 'Favorite color?'
41+
survey = maker.survey
42+
taker = SurveyTaker.new(survey)
43+
sign_in
44+
taker.complete 'Brian', ''
45+
as_another_user { taker.complete 'Billy', 'Red' }
46+
47+
view_summary survey, 'Most Recent'
48+
49+
summary_for_question('Name?').should eq('Billy')
50+
summary_for_question('Favorite color?').
51+
should eq("You haven't answered this question")
52+
53+
show_unanswered_questions
54+
55+
summary_for_question('Favorite color?').
56+
should eq('Red')
57+
end
58+
3759
scenario 'view your answers' do
3860
maker = SurveyMaker.new
3961
maker.open_question 'Name?'
@@ -57,10 +79,15 @@
5779
as_another_user { taker.complete 'Billy' }
5880

5981
view_summary survey, 'Your Answers'
82+
show_unanswered_questions
6083

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

87+
def show_unanswered_questions
88+
click_on "Show questions I haven't answered"
89+
end
90+
6491
def view_summary(survey, type)
6592
visit survey_path(survey)
6693
click_link type

example_app/spec/models/answer_spec.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
describe Answer do
44
it { should belong_to(:completion) }
55
it { should belong_to(:question) }
6-
7-
it { should validate_presence_of(:text) }
86
end
97

108
describe Answer, '.for_user' do

example_app/spec/models/question_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@
1616
it { should have_many(:answers) }
1717
end
1818

19+
describe Question, '#answered_by?' do
20+
it 'returns true for a user with an answer' do
21+
user = create(:user)
22+
question = create(:question)
23+
AnswerCreator.new(question.survey, user: user).answer(question)
24+
25+
question.should be_answered_by(user)
26+
end
27+
28+
it 'returns false for a user without an answer' do
29+
user = create(:user)
30+
other_user = create(:user)
31+
survey = create(:survey)
32+
question = create(:question, survey: survey)
33+
other_question = create(:question, survey: survey)
34+
creator = AnswerCreator.new(survey, user: user)
35+
creator.answer(question, '')
36+
creator.answer(other_question, 'hello')
37+
AnswerCreator.new(survey, user: other_user).answer(question)
38+
39+
question.should_not be_answered_by(user)
40+
end
41+
end
42+
1943
describe Question, '#build_submittable' do
2044
it 'builds a submittable with the given type and attributes' do
2145
expected_value = 1.day.ago

example_app/spec/models/survey_spec.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
it 'applies the given summarizer to each question' do
1212
questions = [build_stubbed(:question), build_stubbed(:question)]
1313
survey = build_stubbed(:survey, questions: questions)
14-
summarizer = stub('summarizer', summarize: 'result')
14+
summarizer = stub_summarizer
1515

1616
result = survey.summaries_using(summarizer)
1717

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

23+
it 'applies the given summarizer to each question answered by the user' do
24+
user = build_stubbed(:user)
25+
answered_question = stub_question(user: user, answered: true)
26+
unanswered_question = stub_question(user: user, answered: false)
27+
questions = [answered_question, unanswered_question]
28+
questions.stubs(:answered_by).with(user).returns(questions)
29+
survey = build_stubbed(:survey, questions: questions)
30+
summarizer = stub_summarizer
31+
32+
result = survey.summaries_using(summarizer, answered_by: user)
33+
34+
should_summarize_questions [answered_question], summarizer
35+
result.map(&:title).should eq questions.map(&:title)
36+
result.map(&:value).
37+
should eq ['result', "You haven't answered this question"]
38+
end
39+
40+
def stub_question(arguments)
41+
build_stubbed(:question).tap do |question|
42+
question.
43+
stubs(:answered_by?).
44+
with(arguments[:user]).
45+
returns(arguments[:answered])
46+
end
47+
end
48+
49+
def stub_summarizer
50+
stub('summarizer', summarize: 'result')
51+
end
52+
2353
def should_summarize_questions(questions, summarizer)
2454
questions.each do |question|
2555
summarizer.should have_received(:summarize).with(question)

example_app/spec/support/answer_creator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def initialize(survey, options = {})
66
@completion = create(:completion, options.merge(survey: @survey))
77
end
88

9-
def answer(question, answer_text)
9+
def answer(question, answer_text = 'hello')
1010
create(
1111
:answer,
1212
question: question,

0 commit comments

Comments
 (0)