Add Model changes to work with votation_types
This commit is contained in:
34
app/models/poll/pair_answer.rb
Normal file
34
app/models/poll/pair_answer.rb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
class Poll::PairAnswer < ApplicationRecord
|
||||||
|
|
||||||
|
belongs_to :question, -> { with_hidden }
|
||||||
|
belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id"
|
||||||
|
belongs_to :answer_right, class_name: "Poll::Question::Answer", foreign_key: "answer_rigth_id"
|
||||||
|
belongs_to :answer_left, class_name: "Poll::Question::Answer", foreign_key: "answer_left_id"
|
||||||
|
|
||||||
|
delegate :poll, :poll_id, to: :question
|
||||||
|
|
||||||
|
validates :question, presence: true
|
||||||
|
validates :author, presence: true
|
||||||
|
validates :answer_left, presence: true
|
||||||
|
validates :answer_right, presence: true
|
||||||
|
|
||||||
|
validates :answer_left, inclusion: { in: ->(a) { a.question.question_answers.visibles }},
|
||||||
|
unless: ->(a) { a.question.blank? }
|
||||||
|
|
||||||
|
validates :answer_right, inclusion: { in: ->(a) { a.question.question_answers.visibles }},
|
||||||
|
unless: ->(a) { a.question.blank? }
|
||||||
|
|
||||||
|
|
||||||
|
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||||
|
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||||
|
|
||||||
|
def self.generate_pair(question, user)
|
||||||
|
answers = question.question_answers.visibles.sample(2)
|
||||||
|
question.pair_answers.by_author(user).map(&:destroy)
|
||||||
|
question.pair_answers.create(author: user, answer_left: answers[0], answer_right: answers[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
def answers
|
||||||
|
[answer_left, answer_right].compact
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,6 +11,7 @@ class Poll::PartialResult < ApplicationRecord
|
|||||||
validates :author, presence: true
|
validates :author, presence: true
|
||||||
validates :answer, presence: true
|
validates :answer, presence: true
|
||||||
validates :answer, inclusion: { in: ->(a) { a.question.question_answers
|
validates :answer, inclusion: { in: ->(a) { a.question.question_answers
|
||||||
|
.visibles
|
||||||
.joins(:translations)
|
.joins(:translations)
|
||||||
.pluck("poll_question_answer_translations.title") }},
|
.pluck("poll_question_answer_translations.title") }},
|
||||||
unless: ->(a) { a.question.blank? }
|
unless: ->(a) { a.question.blank? }
|
||||||
|
|||||||
@@ -15,14 +15,22 @@ class Poll::Question < ApplicationRecord
|
|||||||
has_many :answers, class_name: "Poll::Answer"
|
has_many :answers, class_name: "Poll::Answer"
|
||||||
has_many :question_answers, -> { order "given_order asc" }, class_name: "Poll::Question::Answer", dependent: :destroy
|
has_many :question_answers, -> { order "given_order asc" }, class_name: "Poll::Question::Answer", dependent: :destroy
|
||||||
has_many :partial_results
|
has_many :partial_results
|
||||||
|
has_many :pair_answers, class_name: "Poll::PairAnswer"
|
||||||
|
has_one :votation_type, as: :questionable
|
||||||
belongs_to :proposal
|
belongs_to :proposal
|
||||||
|
|
||||||
|
attr_accessor :enum_type, :max_votes, :prioritization_type
|
||||||
|
|
||||||
validates_translation :title, presence: true, length: { minimum: 4 }
|
validates_translation :title, presence: true, length: { minimum: 4 }
|
||||||
validates :author, presence: true
|
validates :author, presence: true
|
||||||
validates :poll_id, presence: true, if: Proc.new { |question| question.poll.nil? }
|
validates :poll_id, presence: true, if: Proc.new { |question| question.poll.nil? }
|
||||||
|
|
||||||
|
validates_associated :votation_type
|
||||||
accepts_nested_attributes_for :question_answers, reject_if: :all_blank, allow_destroy: true
|
accepts_nested_attributes_for :question_answers, reject_if: :all_blank, allow_destroy: true
|
||||||
|
|
||||||
|
delegate :enum_type, :max_votes, :prioritization_type, :max_groups_answers,
|
||||||
|
to: :votation_type, allow_nil: true
|
||||||
|
|
||||||
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
|
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
|
||||||
|
|
||||||
scope :sort_for_list, -> { order("poll_questions.proposal_id IS NULL", :created_at)}
|
scope :sort_for_list, -> { order("poll_questions.proposal_id IS NULL", :created_at)}
|
||||||
@@ -59,10 +67,24 @@ class Poll::Question < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def answers_total_votes
|
def answers_total_votes
|
||||||
question_answers.inject(0) { |total, question_answer| total + question_answer.total_votes }
|
question_answers.visibles.inject(0) { |total, question_answer| total + question_answer.total_votes }
|
||||||
end
|
end
|
||||||
|
|
||||||
def most_voted_answer_id
|
def most_voted_answer_id
|
||||||
question_answers.max_by { |answer| answer.total_votes }.id
|
question_answers.max_by { |answer| answer.total_votes }.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def answers_with_read_more?
|
||||||
|
question_answers.visibles.any? do |answer| answer.description.present? || answer.images.any? ||
|
||||||
|
answer.documents.present? || answer.videos.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_can_vote(user)
|
||||||
|
max_votes.nil? || max_votes > answers.where(author: user).count
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_positive_negative?
|
||||||
|
votation_type.present? && enum_type == "positive_negative_open"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
class Poll::Question::Answer < ApplicationRecord
|
class Poll::Question::Answer < ApplicationRecord
|
||||||
include Galleryable
|
include Galleryable
|
||||||
include Documentable
|
include Documentable
|
||||||
|
paginates_per 10
|
||||||
|
|
||||||
translates :title, touch: true
|
translates :title, touch: true
|
||||||
translates :description, touch: true
|
translates :description, touch: true
|
||||||
@@ -14,6 +15,10 @@ class Poll::Question::Answer < ApplicationRecord
|
|||||||
validates_translation :title, presence: true
|
validates_translation :title, presence: true
|
||||||
validates :given_order, presence: true, uniqueness: { scope: :question_id }
|
validates :given_order, presence: true, uniqueness: { scope: :question_id }
|
||||||
|
|
||||||
|
scope :by_author, -> (author) { where(author: author) }
|
||||||
|
|
||||||
|
scope :visibles, -> { where(hidden: false) }
|
||||||
|
|
||||||
def description
|
def description
|
||||||
self[:description].try :html_safe
|
self[:description].try :html_safe
|
||||||
end
|
end
|
||||||
@@ -29,11 +34,72 @@ class Poll::Question::Answer < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def total_votes
|
def total_votes
|
||||||
Poll::Answer.where(question_id: question, answer: title).count +
|
if !question.votation_type.present?
|
||||||
::Poll::PartialResult.where(question: question).where(answer: title).sum(:amount)
|
Poll::Answer.where(question_id: question, answer: title).count +
|
||||||
|
::Poll::PartialResult.where(question: question).where(answer: title).sum(:amount)
|
||||||
|
else
|
||||||
|
case question.votation_type.enum_type
|
||||||
|
when "positive_negative_open"
|
||||||
|
total_votes_positive_negative
|
||||||
|
when "prioritized"
|
||||||
|
total_votes_prioritized
|
||||||
|
when "unique"
|
||||||
|
Poll::Answer.where(question_id: question, answer: title).count +
|
||||||
|
::Poll::PartialResult.where(question: question).where(answer: title).sum(:amount)
|
||||||
|
else
|
||||||
|
Poll::Answer.where(question_id: question, answer: title).count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_votes_positive_negative
|
||||||
|
count_positive_negative(self, true) - count_positive_negative(self, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_votes_prioritized
|
||||||
|
Poll::Answer.where(question_id: question, answer: title).sum(:value)
|
||||||
|
end
|
||||||
|
|
||||||
|
def most_voted?
|
||||||
|
most_voted
|
||||||
end
|
end
|
||||||
|
|
||||||
def total_votes_percentage
|
def total_votes_percentage
|
||||||
question.answers_total_votes.zero? ? 0 : (total_votes * 100.0) / question.answers_total_votes
|
question.answers_total_votes.zero? ? 0 : (total_votes * 100.0) / question.answers_total_votes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_most_voted
|
||||||
|
if question.enum_type.nil?
|
||||||
|
for_only_votes
|
||||||
|
else
|
||||||
|
case question.enum_type
|
||||||
|
when "positive_negative_open"
|
||||||
|
answers = question.question_answers.visibles
|
||||||
|
.map { |a| count_positive_negative(a, true) - count_positive_negative(a, false) }
|
||||||
|
is_most_voted = answers.none? {|a| a > total_votes_positive_negative}
|
||||||
|
update(most_voted: is_most_voted)
|
||||||
|
when "prioritized"
|
||||||
|
answers = question.question_answers.visibles
|
||||||
|
.map { |a| Poll::Answer.where(question_id: a.question, answer: a.title).sum(:value) }
|
||||||
|
is_most_voted = answers.none? {|a| a > total_votes_prioritized}
|
||||||
|
update(most_voted: is_most_voted)
|
||||||
|
else
|
||||||
|
for_only_votes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def count_positive_negative(answer, value)
|
||||||
|
Poll::Answer.where(question_id: answer.question, answer: answer.title, positive: value).count
|
||||||
|
end
|
||||||
|
|
||||||
|
def for_only_votes
|
||||||
|
answers = question.question_answers.visibles
|
||||||
|
.map {|a| Poll::Answer.where(question_id: a.question, answer: a.title).count}
|
||||||
|
is_most_voted = answers.none? {|a| a > total_votes}
|
||||||
|
update(most_voted: is_most_voted)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class User < ApplicationRecord
|
|||||||
has_many :follows
|
has_many :follows
|
||||||
has_many :budget_rol_assignments
|
has_many :budget_rol_assignments
|
||||||
has_many :budgets, through: :budget_rol_assignments
|
has_many :budgets, through: :budget_rol_assignments
|
||||||
|
has_many :votation_set_answers
|
||||||
belongs_to :geozone
|
belongs_to :geozone
|
||||||
|
|
||||||
validates :username, presence: true, if: :username_required?
|
validates :username, presence: true, if: :username_required?
|
||||||
|
|||||||
6
app/models/votation_set_answer.rb
Normal file
6
app/models/votation_set_answer.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class VotationSetAnswer < ApplicationRecord
|
||||||
|
belongs_to :votation_type
|
||||||
|
belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id"
|
||||||
|
|
||||||
|
scope :by_author, -> (author) { where(author: author) }
|
||||||
|
end
|
||||||
202
app/models/votation_type.rb
Normal file
202
app/models/votation_type.rb
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
class VotationType < ApplicationRecord
|
||||||
|
belongs_to :questionable, polymorphic: true
|
||||||
|
has_many :votation_set_answers
|
||||||
|
|
||||||
|
QUESTIONABLE_TYPES = %w[Poll::Question].freeze
|
||||||
|
|
||||||
|
ENUM_TYPES_PROPS = {
|
||||||
|
unique: { enum_type: 0, open_answer: false, prioritized: false },
|
||||||
|
multiple: { enum_type: 1, open_answer: false, prioritized: false,
|
||||||
|
variables: [:max_votes] },
|
||||||
|
prioritized: { enum_type: 2, open_answer: false, prioritized: true,
|
||||||
|
variables: [:max_votes, :prioritization_type] },
|
||||||
|
positive_open: { enum_type: 3, open_answer: true, prioritized: false,
|
||||||
|
variables: [:max_votes] },
|
||||||
|
positive_negative_open: { enum_type: 4, open_answer: true, prioritized: false,
|
||||||
|
variables: [:max_votes] },
|
||||||
|
answer_couples_open: { enum_type: 5, open_answer: true, prioritized: false,
|
||||||
|
variables: [:max_votes, :display_skip_question] },
|
||||||
|
answer_couples_closed: { enum_type: 6, open_answer: false, prioritized: false,
|
||||||
|
variables: [:max_votes, :display_skip_question] },
|
||||||
|
answer_set_open: { enum_type: 7, open_answer: true, prioritized: false,
|
||||||
|
variables: [:max_votes, :max_groups_answers] },
|
||||||
|
answer_set_closed: { enum_type: 8, open_answer: false, prioritized: false,
|
||||||
|
variables: [:max_votes, :max_groups_answers] },
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
enum enum_type: ENUM_TYPES_PROPS.map{ |k,v| [k, v[:enum_type]] }.to_h.freeze
|
||||||
|
|
||||||
|
enum prioritization_type: {borda: 1, dowdall: 2}.freeze
|
||||||
|
|
||||||
|
validates :questionable, presence: true
|
||||||
|
validates :questionable_type, inclusion: {in: QUESTIONABLE_TYPES}
|
||||||
|
validates_presence_of :max_votes, allow_blank: false,
|
||||||
|
if: :max_votes_required?
|
||||||
|
validates_presence_of :max_groups_answers, allow_blank: false,
|
||||||
|
if: :max_groups_answers_required?
|
||||||
|
validates_presence_of :prioritization_type, allow_blank: false,
|
||||||
|
if: :prioritization_type_required?
|
||||||
|
|
||||||
|
after_create :add_skip_question_answer, if: :display_skip_question?
|
||||||
|
|
||||||
|
attr_accessor :display_skip_question
|
||||||
|
|
||||||
|
def open?
|
||||||
|
open_answer
|
||||||
|
end
|
||||||
|
|
||||||
|
def prioritized?
|
||||||
|
prioritized
|
||||||
|
end
|
||||||
|
|
||||||
|
def answer (user, answer, options = {})
|
||||||
|
result = nil
|
||||||
|
votes = questionable.answers
|
||||||
|
|
||||||
|
if votable_question?(answer)
|
||||||
|
case enum_type
|
||||||
|
when "unique"
|
||||||
|
result = votes.find_or_initialize_by(author: user)
|
||||||
|
|
||||||
|
when "multiple", "positive_open"
|
||||||
|
if check_max_votes(user, votes)
|
||||||
|
result = votes.find_or_initialize_by(author: user, answer: answer)
|
||||||
|
end
|
||||||
|
|
||||||
|
when "prioritized"
|
||||||
|
result = votes.find_by(author: user, answer: answer)
|
||||||
|
if result.nil?
|
||||||
|
if check_max_votes(user, votes)
|
||||||
|
if votes.by_author(user.id).empty?
|
||||||
|
order = 1
|
||||||
|
else
|
||||||
|
order = votes.by_author(user.id).order(:order).last.order + 1
|
||||||
|
end
|
||||||
|
result = votes.find_or_initialize_by(author: user,
|
||||||
|
answer: answer,
|
||||||
|
order: order)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
!result.update(order: options[:order])
|
||||||
|
end
|
||||||
|
|
||||||
|
when "positive_negative_open"
|
||||||
|
result = votes.by_author(user.id).find_by(answer: answer)
|
||||||
|
if result.nil?
|
||||||
|
if check_max_votes(user, votes)
|
||||||
|
result = votes.create(author: user,
|
||||||
|
answer: answer,
|
||||||
|
positive: options[:positive])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
!result.update(positive: options[:positive])
|
||||||
|
end
|
||||||
|
|
||||||
|
when "answer_couples_closed", "answer_couples_open"
|
||||||
|
if check_max_votes(user, votes)
|
||||||
|
result = votes.create(
|
||||||
|
answer: answer,
|
||||||
|
author: user,
|
||||||
|
positive: true,
|
||||||
|
order: votes&.by_author(user.id).count + 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
Poll::PairAnswer.generate_pair(questionable, user)
|
||||||
|
|
||||||
|
when "answer_set_open", "answer_set_closed"
|
||||||
|
if check_max_votes(user, votes) && answer_in_set?(answer, user)
|
||||||
|
result = votes&.find_or_initialize_by(author: user, answer: answer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_question_answer(answer, hidden=false)
|
||||||
|
return if questionable.question_answers.where(title: answer).any?
|
||||||
|
|
||||||
|
questionable.question_answers
|
||||||
|
.create(
|
||||||
|
title: answer,
|
||||||
|
given_order: questionable.question_answers.maximum(:given_order).to_i + 1,
|
||||||
|
hidden: hidden
|
||||||
|
)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def votable_question?(answer)
|
||||||
|
questionable.question_answers.where(title: answer).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.build_by_type(questionable, params)
|
||||||
|
attributes = {questionable: questionable}
|
||||||
|
enum_type = self.enum_types.key(params[:enum_type].to_i)
|
||||||
|
enum_type_props = enum_properties(enum_type)
|
||||||
|
attributes.merge!(enum_type_props.except(:variables))
|
||||||
|
enum_type_props[:variables]&.each do |property|
|
||||||
|
attributes[property] = params[property]
|
||||||
|
end
|
||||||
|
attributes[:prioritization_type] = attributes[:prioritization_type]&.to_i
|
||||||
|
new(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_by_type(questionable, params)
|
||||||
|
votation_type = build_by_type(questionable, params)
|
||||||
|
votation_type.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_priorized_values(user)
|
||||||
|
case prioritization_type
|
||||||
|
when "borda"
|
||||||
|
questionable.answers.by_author(user).order(:order).each_with_index do |answer, i|
|
||||||
|
value = max_votes - i
|
||||||
|
!answer.update(value: value)
|
||||||
|
end
|
||||||
|
when "dowdall"
|
||||||
|
questionable.answers.by_author(user).order(:order).each_with_index do |answer, i|
|
||||||
|
value = 60/(i + 1)
|
||||||
|
!answer.update(value: value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def answer_in_set?(answer, user)
|
||||||
|
votation_set_answers&.by_author(user)&.pluck(:answer).include?(answer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_max_votes(user, votes)
|
||||||
|
max_votes > votes&.by_author(user.id).count
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.enum_properties(enum_type)
|
||||||
|
ENUM_TYPES_PROPS[enum_type&.to_sym] || ENUM_TYPES_PROPS[:unique]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.enum_properties_variables(enum_type)
|
||||||
|
enum_properties(enum_type)&.dig(:variables)
|
||||||
|
end
|
||||||
|
|
||||||
|
def max_votes_required?
|
||||||
|
VotationType.enum_properties_variables(self.enum_type)&.include?(:max_votes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def max_groups_answers_required?
|
||||||
|
VotationType.enum_properties_variables(self.enum_type)&.include?(:max_groups_answers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def prioritization_type_required?
|
||||||
|
VotationType.enum_properties_variables(self.enum_type)&.include?(:prioritization_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_skip_question?
|
||||||
|
VotationType.enum_properties_variables(self.enum_type)&.include?(:display_skip_question)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_skip_question_answer
|
||||||
|
create_question_answer("I can't decided", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
17
db/migrate/20190513112613_create_votation_types.rb
Normal file
17
db/migrate/20190513112613_create_votation_types.rb
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class CreateVotationTypes < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :votation_types do |t|
|
||||||
|
t.integer :questionable_id
|
||||||
|
t.string :questionable_type
|
||||||
|
t.integer :enum_type
|
||||||
|
t.boolean :open_answer
|
||||||
|
t.boolean :prioritized
|
||||||
|
t.integer :prioritization_type
|
||||||
|
t.integer :max_votes
|
||||||
|
t.integer :max_groups_answers
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class AddOrderAndPositiveInPollAnswers < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_column :poll_answers, :positive, :boolean
|
||||||
|
add_column :poll_answers, :order, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
13
db/migrate/20190522075912_create_poll_pair_answers.rb
Normal file
13
db/migrate/20190522075912_create_poll_pair_answers.rb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
class CreatePollPairAnswers < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :poll_pair_answers do |t|
|
||||||
|
t.references :question, index: true
|
||||||
|
t.references :author, index: true
|
||||||
|
t.references :answer_rigth
|
||||||
|
t.references :answer_left
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class AddHiddenFieldToPollQuestionAnswers < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_column :poll_question_answers, :hidden, :boolean, default: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
6
db/migrate/20190524121957_add_value_to_poll_answers.rb
Normal file
6
db/migrate/20190524121957_add_value_to_poll_answers.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class AddValueToPollAnswers < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_column :poll_answers, :value, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
12
db/migrate/20190528134530_create_votation_set_answers.rb
Normal file
12
db/migrate/20190528134530_create_votation_set_answers.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
class CreateVotationSetAnswers < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :votation_set_answers do |t|
|
||||||
|
t.integer :author_id, index: true
|
||||||
|
t.references :votation_type, foreign_key: true, index: true
|
||||||
|
t.string :answer
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
41
db/schema.rb
41
db/schema.rb
@@ -1029,6 +1029,9 @@ ActiveRecord::Schema.define(version: 20190607160900) do
|
|||||||
t.string "answer"
|
t.string "answer"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
|
t.boolean "positive"
|
||||||
|
t.integer "order"
|
||||||
|
t.integer "value"
|
||||||
t.index ["author_id"], name: "index_poll_answers_on_author_id", using: :btree
|
t.index ["author_id"], name: "index_poll_answers_on_author_id", using: :btree
|
||||||
t.index ["question_id", "answer"], name: "index_poll_answers_on_question_id_and_answer", using: :btree
|
t.index ["question_id", "answer"], name: "index_poll_answers_on_question_id_and_answer", using: :btree
|
||||||
t.index ["question_id"], name: "index_poll_answers_on_question_id", using: :btree
|
t.index ["question_id"], name: "index_poll_answers_on_question_id", using: :btree
|
||||||
@@ -1084,6 +1087,19 @@ ActiveRecord::Schema.define(version: 20190607160900) do
|
|||||||
t.index ["user_id"], name: "index_poll_officers_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_poll_officers_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "poll_pair_answers", force: :cascade do |t|
|
||||||
|
t.integer "question_id"
|
||||||
|
t.integer "author_id"
|
||||||
|
t.integer "answer_rigth_id"
|
||||||
|
t.integer "answer_left_id"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["answer_left_id"], name: "index_poll_pair_answers_on_answer_left_id", using: :btree
|
||||||
|
t.index ["answer_rigth_id"], name: "index_poll_pair_answers_on_answer_rigth_id", using: :btree
|
||||||
|
t.index ["author_id"], name: "index_poll_pair_answers_on_author_id", using: :btree
|
||||||
|
t.index ["question_id"], name: "index_poll_pair_answers_on_question_id", using: :btree
|
||||||
|
end
|
||||||
|
|
||||||
create_table "poll_partial_results", force: :cascade do |t|
|
create_table "poll_partial_results", force: :cascade do |t|
|
||||||
t.integer "question_id"
|
t.integer "question_id"
|
||||||
t.integer "author_id"
|
t.integer "author_id"
|
||||||
@@ -1127,6 +1143,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do
|
|||||||
t.integer "question_id"
|
t.integer "question_id"
|
||||||
t.integer "given_order", default: 1
|
t.integer "given_order", default: 1
|
||||||
t.boolean "most_voted", default: false
|
t.boolean "most_voted", default: false
|
||||||
|
t.boolean "hidden", default: false
|
||||||
t.index ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree
|
t.index ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1613,6 +1630,29 @@ ActiveRecord::Schema.define(version: 20190607160900) do
|
|||||||
t.index ["user_id"], name: "index_visits_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_visits_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "votation_set_answers", force: :cascade do |t|
|
||||||
|
t.integer "author_id"
|
||||||
|
t.integer "votation_type_id"
|
||||||
|
t.string "answer"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["author_id"], name: "index_votation_set_answers_on_author_id", using: :btree
|
||||||
|
t.index ["votation_type_id"], name: "index_votation_set_answers_on_votation_type_id", using: :btree
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "votation_types", force: :cascade do |t|
|
||||||
|
t.integer "questionable_id"
|
||||||
|
t.string "questionable_type"
|
||||||
|
t.integer "enum_type"
|
||||||
|
t.boolean "open_answer"
|
||||||
|
t.boolean "prioritized"
|
||||||
|
t.integer "prioritization_type"
|
||||||
|
t.integer "max_votes"
|
||||||
|
t.integer "max_groups_answers"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
end
|
||||||
|
|
||||||
create_table "votes", force: :cascade do |t|
|
create_table "votes", force: :cascade do |t|
|
||||||
t.string "votable_type"
|
t.string "votable_type"
|
||||||
t.integer "votable_id"
|
t.integer "votable_id"
|
||||||
@@ -1721,4 +1761,5 @@ ActiveRecord::Schema.define(version: 20190607160900) do
|
|||||||
add_foreign_key "trackers", "users"
|
add_foreign_key "trackers", "users"
|
||||||
add_foreign_key "users", "geozones"
|
add_foreign_key "users", "geozones"
|
||||||
add_foreign_key "valuators", "users"
|
add_foreign_key "valuators", "users"
|
||||||
|
add_foreign_key "votation_set_answers", "votation_types"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -38,6 +38,69 @@ FactoryBot.define do
|
|||||||
create(:poll_question_answer, question: question, title: "No")
|
create(:poll_question_answer, question: question, title: "No")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :poll_question_unique do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_unique, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_multiple do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_multiple, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_prioritized do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_prioritized, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_positive_open do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_positive_open, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_positive_negative_open do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_positive_negative_open, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_answer_couples_open do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_answer_couples_open, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_answer_couples_closed do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_answer_couples_closed, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_answer_set_open do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_answer_set_open, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :poll_question_answer_set_closed do
|
||||||
|
after(:create) do |question|
|
||||||
|
create(:votation_type_answer_set_closed, questionable: question)
|
||||||
|
question.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :poll_question_answer, class: "Poll::Question::Answer" do
|
factory :poll_question_answer, class: "Poll::Question::Answer" do
|
||||||
@@ -177,4 +240,11 @@ FactoryBot.define do
|
|||||||
|
|
||||||
factory :active_poll do
|
factory :active_poll do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :poll_pair_answer, class: "Poll::PairAnswer" do
|
||||||
|
question { create :poll_question }
|
||||||
|
author { create :user }
|
||||||
|
answer_left { create(:poll_question_answer, question: question) }
|
||||||
|
answer_right { create(:poll_question_answer, question: question) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
76
spec/factories/votation_type.rb
Normal file
76
spec/factories/votation_type.rb
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
FactoryBot.define do
|
||||||
|
factory :votation_type do
|
||||||
|
factory :votation_type_unique do
|
||||||
|
enum_type "unique"
|
||||||
|
open_answer false
|
||||||
|
prioritized false
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_multiple do
|
||||||
|
enum_type "multiple"
|
||||||
|
open_answer false
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_prioritized do
|
||||||
|
enum_type "prioritized"
|
||||||
|
open_answer false
|
||||||
|
prioritized true
|
||||||
|
max_votes 5
|
||||||
|
prioritization_type "borda"
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_positive_open do
|
||||||
|
enum_type "positive_open"
|
||||||
|
open_answer true
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_positive_negative_open do
|
||||||
|
enum_type "answer_couples_open"
|
||||||
|
open_answer true
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_answer_couples_open do
|
||||||
|
enum_type "answer_couples_open"
|
||||||
|
open_answer true
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_answer_couples_closed do
|
||||||
|
enum_type "answer_couples_open"
|
||||||
|
open_answer false
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_answer_set_open do
|
||||||
|
enum_type "answer_set_open"
|
||||||
|
open_answer true
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
max_groups_answers 3
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :votation_type_answer_set_closed do
|
||||||
|
enum_type "answer_set_open"
|
||||||
|
open_answer false
|
||||||
|
prioritized false
|
||||||
|
max_votes 5
|
||||||
|
max_groups_answers 3
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :open do
|
||||||
|
open_answer true
|
||||||
|
end
|
||||||
|
trait :prioritized do
|
||||||
|
prioritized true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
131
spec/models/poll/pair_answer_spec.rb
Normal file
131
spec/models/poll/pair_answer_spec.rb
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe Poll::PairAnswer do
|
||||||
|
|
||||||
|
describe "validations" do
|
||||||
|
|
||||||
|
let(:pair_answer) { build(:poll_pair_answer) }
|
||||||
|
|
||||||
|
it "is valid" do
|
||||||
|
expect(pair_answer).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid wihout a question" do
|
||||||
|
pair_answer.question = nil
|
||||||
|
|
||||||
|
expect(pair_answer).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid without an author" do
|
||||||
|
pair_answer.author = nil
|
||||||
|
|
||||||
|
expect(pair_answer).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is valid if answer_left is included in the Poll::Question's question_answers list" do
|
||||||
|
question = create(:poll_question)
|
||||||
|
answer1 = create(:poll_question_answer, title: "One", question: question)
|
||||||
|
answer2 = create(:poll_question_answer, title: "Two", question: question)
|
||||||
|
answer3 = create(:poll_question_answer, title: "Three")
|
||||||
|
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_left: answer1)).to be_valid
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_left: answer2)).to be_valid
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_left: answer3)).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is valid if answer_right is included in the Poll::Question's question_answers list" do
|
||||||
|
question = create(:poll_question)
|
||||||
|
answer1 = create(:poll_question_answer, title: "One", question: question)
|
||||||
|
answer2 = create(:poll_question_answer, title: "Two", question: question)
|
||||||
|
answer3 = create(:poll_question_answer, title: "Three")
|
||||||
|
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_right: answer1)).to be_valid
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_right: answer2)).to be_valid
|
||||||
|
expect(build(:poll_pair_answer, question: question, answer_right: answer3)).not_to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "scopes" do
|
||||||
|
let(:pair_answer_1) { create(:poll_pair_answer) }
|
||||||
|
let(:pair_answer_2) { create(:poll_pair_answer) }
|
||||||
|
|
||||||
|
describe "#by_author" do
|
||||||
|
|
||||||
|
it "returns pair_answers associated to an user" do
|
||||||
|
author = pair_answer_1.author
|
||||||
|
|
||||||
|
expect(described_class.by_author(author)).to include(pair_answer_1)
|
||||||
|
expect(described_class.by_author(author)).not_to include(pair_answer_2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#by_question" do
|
||||||
|
|
||||||
|
it "returns pair_answers associated to a question" do
|
||||||
|
question = pair_answer_1.question
|
||||||
|
|
||||||
|
expect(described_class.by_question(question)).to include(pair_answer_1)
|
||||||
|
expect(described_class.by_question(question)).not_to include(pair_answer_2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "#generate_pair" do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:question) { create(:poll_question) }
|
||||||
|
|
||||||
|
context "without question_answers" do
|
||||||
|
|
||||||
|
it "assigns nil value to pair_answers" do
|
||||||
|
pair_answer = described_class.generate_pair(question, user)
|
||||||
|
|
||||||
|
expect(pair_answer).to be_a Poll::PairAnswer
|
||||||
|
expect(pair_answer.question).to eq(question)
|
||||||
|
expect(pair_answer.author).to eq(user)
|
||||||
|
expect(pair_answer.answer_left).to be_nil
|
||||||
|
expect(pair_answer.answer_right).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "With question answers" do
|
||||||
|
let!(:answer1) { create(:poll_question_answer, question: question) }
|
||||||
|
|
||||||
|
it "assigns only right question if only has one question_answer" do
|
||||||
|
pair_answer = described_class.generate_pair(question, user)
|
||||||
|
|
||||||
|
expect(pair_answer).to be_a Poll::PairAnswer
|
||||||
|
expect(pair_answer.question).to eq(question)
|
||||||
|
expect(pair_answer.author).to eq(user)
|
||||||
|
expect(pair_answer.answer_left).to eq(answer1)
|
||||||
|
expect(pair_answer.answer_right).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "assigns random values if question has some question_answer" do
|
||||||
|
create(:poll_question_answer, question: question)
|
||||||
|
|
||||||
|
pair_answer = described_class.generate_pair(question, user)
|
||||||
|
|
||||||
|
expect(pair_answer).to be_a Poll::PairAnswer
|
||||||
|
expect(pair_answer.question).to eq(question)
|
||||||
|
expect(pair_answer.author).to eq(user)
|
||||||
|
expect(pair_answer.answer_left).to be_a Poll::Question::Answer
|
||||||
|
expect(pair_answer.answer_right).to be_a Poll::Question::Answer
|
||||||
|
expect(pair_answer.answer_left).not_to eq(pair_answer.answer_right)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#answers" do
|
||||||
|
let(:pair_answer) { create(:poll_pair_answer) }
|
||||||
|
|
||||||
|
it "returns and array of answers" do
|
||||||
|
expect(pair_answer.answers).to be_a Array
|
||||||
|
expect(pair_answer.answers[0]).to eq(pair_answer.answer_left)
|
||||||
|
expect(pair_answer.answers[1]).to eq(pair_answer.answer_right)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -44,4 +44,35 @@ RSpec.describe Poll::Question, type: :model do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#enum_type" do
|
||||||
|
|
||||||
|
it "returns nil if not has votation_type association" do
|
||||||
|
expect(poll_question.votation_type).to be_nil
|
||||||
|
expect(poll_question.enum_type).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns enum_type from votation_type association" do
|
||||||
|
question = create(:poll_question_answer_couples_open)
|
||||||
|
|
||||||
|
expect(question.votation_type).not_to be_nil
|
||||||
|
expect(question.enum_type).to eq("answer_couples_open")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#max_votes" do
|
||||||
|
|
||||||
|
it "returns nil if not has votation_type association" do
|
||||||
|
expect(poll_question.votation_type).to be_nil
|
||||||
|
expect(poll_question.max_votes).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns max_votes from votation_type association" do
|
||||||
|
question = create(:poll_question_answer_couples_open)
|
||||||
|
|
||||||
|
expect(question.votation_type).not_to be_nil
|
||||||
|
expect(question.max_votes).to eq(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user