Skip to content
This repository has been archived by the owner on Feb 27, 2019. It is now read-only.

Commit

Permalink
Finished implementation of multiple choice support.
Browse files Browse the repository at this point in the history
  • Loading branch information
boborbt committed Jan 10, 2012
1 parent 27e36b6 commit c0b78dc
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 49 deletions.
13 changes: 8 additions & 5 deletions app/controllers/answers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ def new
def create
@activation_code = ActivationCode.find_by_code( params[:activation_code][:code] )
@answer = Answer.find( params[:answer][:id] )
@question = @answer.question

raise "Trying to use an unassigned code" if !@activation_code.consumed

redirect_to( bad_user_path ) && return if @activation_code.nil?
redirect_to( bad_answer_path ) && return if @answer.activation_code.nil? || @activation_code != @answer.activation_code


@answer.assign_alternatives!(params[:selected_alternatives].keys)


redirect_to :action => :new, :activation_code => { :code => @activation_code.code }
sel_alts = params[:selected_alternatives]
if @answer.assign_choices(sel_alts && sel_alts.keys)
redirect_to :action => :new, :activation_code => { :code => @activation_code.code }
else
render :action => :new
end
end
end
2 changes: 1 addition & 1 deletion app/models/activation_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def associate_answers!
end

def poll_completed?
answers.all? { |a| !a.alternative_id.blank? }
answers.all? { |a| !a.choices.blank? }
end

def next_answer
Expand Down
40 changes: 27 additions & 13 deletions app/models/answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,44 @@
# along with SondaggioStatuto. If not, see <http://www.gnu.org/licenses/>.

class Answer < ActiveRecord::Base
belongs_to :alternative
belongs_to :question
belongs_to :activation_code

named_scope :filled_answers, :conditions => 'alternative_id is not NULL'
named_scope :assignable_answers, :conditions => 'activation_code_id is NULL AND alternative_id is NULL'
named_scope :filled_answers, :conditions => 'choices is not NULL'
named_scope :assignable_answers, :conditions => 'activation_code_id is NULL AND choices is NULL'

def assign_alternatives!(alternative_ids)
# FIXME: Support more than one alternative!
puts "Warn! Look at the FIXME"
alternative_id = alternative_ids[0]

def validate
unless choices.nil? || choices.size <= question.num_choices
errors.add_to_base("Il numero di scelte (attualmente #{choices.size}) deve essere minore o uguale a #{question.num_choices}")
end
end

def choices
self['choices'] && self['choices'].split(',').map { |c| c.to_i } || nil
end

def choices= values
self['choices'] = (values.nil? ? nil : values.join(','))
end

def assign_choices(alternative_ids)
result = nil
Answer.transaction do
self.activation_code = nil
self.alternative_id = alternative_id
self.save!
self.choices = alternative_ids
result = self.save
raise ActiveRecord::Rollback unless result
end

result
end

def Answer.stats
alt_stats = {}
Alternative.all.each do |a|
alt_stats[a.question_id] ||= {}
alt_stats[a.question_id][a.id] = Answer.count(:conditions => {:alternative_id => a.id})
valid_answers = Answer.all(:conditions => 'choices IS NOT NULL')
Alternative.all.each do |alt|
alt_stats[alt.question_id] ||= {}
alt_stats[alt.question_id][alt.id] = valid_answers.find_all { |answer| answer.choices.include?(alt.id) }.count
end

alt_stats
Expand Down
4 changes: 2 additions & 2 deletions app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class Question < ActiveRecord::Base
has_many :answers

validates_presence_of :sort_id
validates_inclusion_of :kind, :in => %w{ multichoice singlechoice }
validates_presence_of :num_choices

def filled_answers
answers.find(:all, :conditions => 'alternative_id IS NOT NULL')
answers.find(:all, :conditions => 'choices IS NOT NULL')
end
end
4 changes: 3 additions & 1 deletion app/views/answers/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
</div>

<% form_tag({:controller => 'answers', :action => "create"}) do %>
<%= error_messages_for 'answer' %>
<%= hidden_field :answer, :id %>
<%= hidden_field :activation_code, :code %>
<% @question.alternatives.each_with_index do |alternative, index|
@alternative = alternative %>
<%= check_box_tag("selected_alternatives[#{@alternative.id}]") %> <%= @alternative.text %><br/>
<%= check_box_tag("selected_alternatives[#{@alternative.id}]") %>
<%= label_tag("selected_alternatives[#{@alternative.id}]", @alternative.text) %><br/>
<% end %>
<%= submit_tag 'Confermo' %>
Expand Down
4 changes: 2 additions & 2 deletions db/migrate/20120110104912_add_kind_to_question.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
class AddKindToQuestion < ActiveRecord::Migration
def self.up
add_column :questions, :kind, :string
add_column :questions, :num_choices, :integer
end

def self.down
remove_column :questions, :kind
remove_column :questions, :num_choices
end
end
11 changes: 11 additions & 0 deletions db/migrate/20120110143509_remove_alternative_id_from_answer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class RemoveAlternativeIdFromAnswer < ActiveRecord::Migration
def self.up
remove_column :answers, :alternative_id
add_column :answers, :choices, :string
end

def self.down
remove_column :answers, :choices
add_column :answers, :alternative_id, :integer
end
end
2 changes: 1 addition & 1 deletion script/add_poll_questions_elections.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
q1alt3 = %q{Leo}
q1alt4 = %q{Gigi}

q1 = Question.create!( :text => q1text, :sort_id => 1, :kind => 'multichoice' )
q1 = Question.create!( :text => q1text, :sort_id => 1, :num_choices => 2 )
q1.alternatives << Alternative.create!( :text => q1alt1 )
q1.alternatives << Alternative.create!( :text => q1alt2 )
q1.alternatives << Alternative.create!( :text => q1alt3 )
Expand Down
15 changes: 7 additions & 8 deletions test/integration/poll_usage_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ class PollUsageTest < ActionController::IntegrationTest
def setup
ApplicationConfig.state = :open

@q1 = Question.create( :text => 'q1', :sort_id => 1, :kind => 'singlechoice')
@q1 = Question.create( :text => 'q1', :sort_id => 1, :num_choices => 1)
@q1.alternatives << Alternative.new( :text => 'q1 a1' )
@q1.alternatives << Alternative.new( :text => 'q1 a2' )

@q2 = Question.create( :text => 'q2', :sort_id => 2, :kind => 'singlechoice')
@q2 = Question.create( :text => 'q2', :sort_id => 2, :num_choices => 1)
@q2.alternatives << Alternative.new( :text => 'q2 a1' )
@q2.alternatives << Alternative.new( :text => 'q2 a2' )

Expand Down Expand Up @@ -85,19 +85,18 @@ def setup
assert page.has_content?('q1 a1')
assert page.has_content?('q1 a2')
assert !page.has_content?('q2')
check('selected_alternatives[1]')
check('q1 a1')
click_on('Confermo')

assert page.has_content?('q2')
assert page.has_content?('q2 a1')
assert page.has_content?('q2 a2')
assert !page.has_content?('q1')
Capybara.save_and_open_page
check('selected_alternatives[4]')
check('q2 a2')
click_on('Confermo')

assert @q1.filled_answers[0].alternative == Alternative.find_by_text('q1 a1')
assert @q2.filled_answers[0].alternative == Alternative.find_by_text('q2 a2')
assert_equal @q1.filled_answers[0].choices, [Alternative.find_by_text('q1 a1').id]
assert_equal @q2.filled_answers[0].choices, [Alternative.find_by_text('q2 a2').id]


assert page.has_content?('Sondaggio completato')
Expand Down Expand Up @@ -160,7 +159,7 @@ def setup
select_alternatives([1,0])
select_alternatives([0,1])
select_alternatives([1,0])

assert_equal 2,Answer.stats[@q1.id][@q1.alternatives[0].id]
assert_equal 2,Answer.stats[@q1.id][@q1.alternatives[1].id]
assert_equal 3,Answer.stats[@q2.id][@q2.alternatives[0].id]
Expand Down
26 changes: 13 additions & 13 deletions test/unit/activation_code_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
class ActivationCodeTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "#generate_answers should generate one answer for each question and they are in the correct order" do
Question.create( :text => 'q1', :sort_id => 1, :kind => 'singlechoice')
Question.create( :text => 'q2', :sort_id => 2, :kind => 'singlechoice')
Question.create( :text => 'q1', :sort_id => 1, :num_choices => 1)
Question.create( :text => 'q2', :sort_id => 2, :num_choices => 1)

ac = ActivationCode.new
assert_equal 0, ac.answers.size
Expand All @@ -34,8 +34,8 @@ class ActivationCodeTest < ActiveSupport::TestCase
end

test '#completed_questionary? should return false if any of the answers is blank' do
Question.create( :text => 'q1', :sort_id => 1, :kind => 'singlechoice')
Question.create( :text => 'q2', :sort_id => 2, :kind => 'singlechoice')
Question.create( :text => 'q1', :sort_id => 1, :num_choices => 1)
Question.create( :text => 'q2', :sort_id => 2, :num_choices => 1)

ac = ActivationCode.new
ac.generate_sha!
Expand All @@ -46,23 +46,23 @@ class ActivationCodeTest < ActiveSupport::TestCase
end

test '#completed_questionary? should return true if all of answers are non-blank' do
Question.create( :text => 'q1', :sort_id => 1, :kind => 'singlechoice')
Question.create( :text => 'q2', :sort_id => 2, :kind => 'singlechoice')
Question.create( :text => 'q1', :sort_id => 1, :num_choices => 1)
Question.create( :text => 'q2', :sort_id => 2, :num_choices => 1)

ac = ActivationCode.new
ac.generate_answers!
ac.generate_sha!
ac.associate_answers!

ac.answers[0].alternative_id = 0
ac.answers[1].alternative_id = 0
ac.answers[0].choices = [0]
ac.answers[1].choices = [0]

assert ac.poll_completed?
end

test 'ApplicationConfig#next_answer should return the first non-blank answer in question.sort_id order' do
Question.create( :text => 'q1', :sort_id => 2, :kind => 'singlechoice')
Question.create( :text => 'q2', :sort_id => 1, :kind => 'singlechoice')
Question.create( :text => 'q1', :sort_id => 2, :num_choices => 1)
Question.create( :text => 'q2', :sort_id => 1, :num_choices => 1)

ac = ActivationCode.new
ac.generate_sha!
Expand All @@ -77,7 +77,7 @@ class ActivationCodeTest < ActiveSupport::TestCase
next_answer = ac.next_answer
assert_equal 1, next_answer.question.sort_id # should still the number 1, since we did not completed it yet

next_answer.assign_alternatives!([2])
next_answer.assign_choices([2])
next_answer.save!

ac.reload
Expand Down Expand Up @@ -115,8 +115,8 @@ class ActivationCodeTest < ActiveSupport::TestCase
end

test "associate_answers! should associate one answer for each question and make them unavailable to others" do
Question.create( :text => 'q1', :sort_id => 2, :kind => 'singlechoice')
Question.create( :text => 'q2', :sort_id => 1, :kind => 'singlechoice')
Question.create( :text => 'q1', :sort_id => 2, :num_choices => 1)
Question.create( :text => 'q2', :sort_id => 1, :num_choices => 1)
ac = ActivationCode.new( :consumed => false )

ac.generate_answers!
Expand Down
27 changes: 24 additions & 3 deletions test/unit/answer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,29 @@
require 'test_helper'

class AnswerTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
def setup
@alt1 = Alternative.create
@alt2 = Alternative.create
@alt3 = Alternative.create
@alt4 = Alternative.create

@q = Question.create!( :sort_id => 1, :num_choices => 2 )
@a = Answer.create!(:question => @q)
end

test "assign choices should store the given vector of alternative ids" do
@a.choices = [@alt1.id, @alt3.id]
@a.save!

assert_equal @a.choices, [@alt1.id, @alt3.id]
end

test "assign choices should support abstined votes" do
assert @a.choices.nil?

@a.choices = []
@a.save!

assert_equal @a.choices, []
end
end

0 comments on commit c0b78dc

Please sign in to comment.