Rename Poll::Question::Answer to Poll::Question::Option

Having a class named `Poll::Question::Answer` and another class named
`Poll::Answer` was so confusing that no developer working on the project
has ever been capable of remembering which is which for more than a few
seconds.

Furthermore, we're planning to add open answers to polls, and we might
add a reference from the `poll_answers` table to the
`poll_question_answers` table to property differentiate between open
answers and closed answers. Having yet another thing named answer would
be more than what our brains can handle (we know it because we did this
once in a prototype).

So we're renaming `Poll::Question::Answer` to `Poll::Question::Option`.
Hopefully that'll make it easier to remember. The name is also (more or
less) consistent with the `Legislation::QuestionOption` class, which is
similar.

We aren't changing the table or columns names for now in order to avoid
possible issues when upgrading (old code running with the new database
tables/columns after running the migrations but before deployment has
finished, for instance). We might do it in the future.

I've tried not to change the internationalization keys either so
existing translations would still be valid. However, since we have to
change the keys in `activerecord.yml` so methods like
`human_attribute_name` keep working, I'm also changing them in places
where similar keys were used (like `poll_question_answer` or
`poll/question/answer`).

Note that it isn't clear whether we should use `option` or
`question_option` in some cases. In order to keep things simple, we're
using `option` where we were using `answer` and `question_option` where
we were using `question_answer`.

Also note we're adding tests for the admin menu component, since at
first I forgot to change the `answers` reference there and all tests
passed.
This commit is contained in:
Javi Martín
2024-05-13 17:38:43 +02:00
parent 6188281d33
commit 38b38d1fcc
100 changed files with 676 additions and 655 deletions

View File

@@ -89,7 +89,7 @@
//= require markdown_editor
//= require html_editor
//= require cocoon
//= require answers
//= require options
//= require questions
//= require legislation_admin
//= require legislation
@@ -129,7 +129,7 @@
var initialize_modules = function() {
"use strict";
App.Answers.initialize();
App.Options.initialize();
App.Questions.initialize();
App.Comments.initialize();
App.ParticipationNotAllowed.initialize();

View File

@@ -1,10 +1,10 @@
(function() {
"use strict";
App.Answers = {
initializeAnswers: function(answers) {
App.Options = {
initializeOptions: function(answers) {
$(answers).on("cocoon:after-insert", function(e, new_answer) {
var given_order;
given_order = App.Answers.maxGivenOrder(answers) + 1;
given_order = App.Options.maxGivenOrder(answers) + 1;
$(new_answer).find("[name$='[given_order]']").val(given_order);
});
},
@@ -18,13 +18,13 @@
});
return max_order;
},
nestedAnswers: function() {
nestedOptions: function() {
$(".js-answers").each(function(index, answers) {
App.Answers.initializeAnswers(answers);
App.Options.initializeOptions(answers);
});
},
initialize: function() {
App.Answers.nestedAnswers();
App.Options.nestedOptions();
}
};
}).call(this);

View File

@@ -3,7 +3,7 @@
App.Questions = {
nestedQuestions: function() {
$(".js-questions").on("cocoon:after-insert", function(e, new_question) {
App.Answers.initializeAnswers($(new_question).find(".js-answers"));
App.Options.initializeOptions($(new_question).find(".js-answers"));
});
},
initialize: function() {

View File

@@ -39,8 +39,8 @@ class Admin::MenuComponent < ApplicationComponent
end
def polls?
controller.class.module_parent == Admin::Poll::Questions::Answers ||
%w[polls active_polls recounts results questions answers].include?(controller_name) &&
controller.class.module_parent == Admin::Poll::Questions::Options ||
%w[polls active_polls recounts results questions options].include?(controller_name) &&
action_name != "booth_assignments"
end
@@ -62,7 +62,7 @@ class Admin::MenuComponent < ApplicationComponent
controllers_names = ["pages", "banners", "information_texts", "documents", "images", "content_blocks"]
(controllers_names.include?(controller_name) || homepage? || pages?) &&
controller.class.module_parent != Admin::Poll::Questions::Answers
controller.class.module_parent != Admin::Poll::Questions::Options
end
def homepage?
@@ -515,7 +515,7 @@ class Admin::MenuComponent < ApplicationComponent
[
t("admin.menu.site_customization.images"),
admin_site_customization_images_path,
controller_name == "images" && controller.class.module_parent != Admin::Poll::Questions::Answers
controller_name == "images" && controller.class.module_parent != Admin::Poll::Questions::Options
]
end

View File

@@ -1,14 +0,0 @@
class Admin::Poll::Questions::Answers::Documents::IndexComponent < ApplicationComponent
attr_reader :answer
use_helpers :can?
def initialize(answer)
@answer = answer
end
private
def documents
@documents ||= @answer.class.find(@answer.id).documents
end
end

View File

@@ -1 +0,0 @@
<%= render Admin::AllowedTableActionsComponent.new(answer) %>

View File

@@ -1,7 +0,0 @@
class Admin::Poll::Questions::Answers::TableActionsComponent < ApplicationComponent
attr_reader :answer
def initialize(answer)
@answer = answer
end
end

View File

@@ -1,16 +1,16 @@
<%= back_link_to admin_question_path(answer.question) %>
<%= back_link_to admin_question_path(option.question) %>
<h2><%= t("admin.questions.show.answers.documents_list") %></h2>
<ul class="breadcrumbs">
<li><%= answer.question.title %></li>
<li><%= answer.title %></li>
<li><%= option.question.title %></li>
<li><%= option.title %></li>
</ul>
<div class="poll-question-form">
<% if can?(:update, answer) %>
<%= form_for(Poll::Question::Answer.new, url: admin_answer_documents_path(answer)) do |f| %>
<%= render "shared/errors", resource: answer %>
<% if can?(:update, option) %>
<%= form_for(Poll::Question::Option.new, url: admin_option_documents_path(option)) do |f| %>
<%= render "shared/errors", resource: option %>
<%= render Documents::NestedComponent.new(f) %>
@@ -37,7 +37,7 @@
<%= document.title %>
</td>
<td>
<%= render Admin::Poll::Questions::Answers::Documents::TableActionsComponent.new(document) %>
<%= render Admin::Poll::Questions::Options::Documents::TableActionsComponent.new(document) %>
</td>
</tr>
<% end %>

View File

@@ -0,0 +1,14 @@
class Admin::Poll::Questions::Options::Documents::IndexComponent < ApplicationComponent
attr_reader :option
use_helpers :can?
def initialize(option)
@option = option
end
private
def documents
@documents ||= @option.class.find(@option.id).documents
end
end

View File

@@ -1,4 +1,4 @@
class Admin::Poll::Questions::Answers::Documents::TableActionsComponent < ApplicationComponent
class Admin::Poll::Questions::Options::Documents::TableActionsComponent < ApplicationComponent
attr_reader :document
def initialize(document)

View File

@@ -0,0 +1 @@
<%= render Admin::AllowedTableActionsComponent.new(option) %>

View File

@@ -0,0 +1,7 @@
class Admin::Poll::Questions::Options::TableActionsComponent < ApplicationComponent
attr_reader :option
def initialize(option)
@option = option
end
end

View File

@@ -1,4 +1,4 @@
class Admin::Poll::Questions::Answers::Videos::TableActionsComponent < ApplicationComponent
class Admin::Poll::Questions::Options::Videos::TableActionsComponent < ApplicationComponent
attr_reader :video
def initialize(video)

View File

@@ -1,35 +1,35 @@
<div class="poll-question-answers">
<% if can?(:answer, question) && !question.poll.voted_in_booth?(current_user) %>
<% question_answers.each do |question_answer| %>
<% if already_answered?(question_answer) %>
<%= button_to question_answer.title,
question_answer_path(question, user_answer(question_answer)),
<% question_options.each do |question_option| %>
<% if already_answered?(question_option) %>
<%= button_to question_option.title,
question_answer_path(question, user_answer(question_option)),
method: :delete,
remote: true,
title: t("poll_questions.show.voted", answer: question_answer.title),
title: t("poll_questions.show.voted", answer: question_option.title),
class: "button answered",
"aria-pressed": true %>
<% else %>
<%= button_to question_answer.title,
answer_question_path(question, answer: question_answer.title),
<%= button_to question_option.title,
answer_question_path(question, answer: question_option.title),
remote: true,
title: t("poll_questions.show.vote_answer", answer: question_answer.title),
title: t("poll_questions.show.vote_answer", answer: question_option.title),
class: "button secondary hollow",
"aria-pressed": false,
disabled: disable_answer?(question_answer) %>
disabled: disable_answer?(question_option) %>
<% end %>
<% end %>
<% elsif !user_signed_in? %>
<% question_answers.each do |question_answer| %>
<%= link_to question_answer.title, new_user_session_path, class: "button secondary hollow" %>
<% question_options.each do |question_option| %>
<%= link_to question_option.title, new_user_session_path, class: "button secondary hollow" %>
<% end %>
<% elsif !current_user.level_two_or_three_verified? %>
<% question_answers.each do |question_answer| %>
<%= link_to question_answer.title, verification_path, class: "button secondary hollow" %>
<% question_options.each do |question_option| %>
<%= link_to question_option.title, verification_path, class: "button secondary hollow" %>
<% end %>
<% else %>
<% question_answers.each do |question_answer| %>
<span class="button secondary hollow disabled"><%= question_answer.title %></span>
<% question_options.each do |question_option| %>
<span class="button secondary hollow disabled"><%= question_option.title %></span>
<% end %>
<% end %>
</div>

View File

@@ -1,4 +1,4 @@
class Polls::Questions::AnswersComponent < ApplicationComponent
class Polls::Questions::OptionsComponent < ApplicationComponent
attr_reader :question
use_helpers :can?, :current_user, :user_signed_in?
@@ -6,19 +6,19 @@ class Polls::Questions::AnswersComponent < ApplicationComponent
@question = question
end
def already_answered?(question_answer)
user_answer(question_answer).present?
def already_answered?(question_option)
user_answer(question_option).present?
end
def question_answers
question.question_answers
def question_options
question.question_options
end
def user_answer(question_answer)
user_answers.find_by(answer: question_answer.title)
def user_answer(question_option)
user_answers.find_by(answer: question_option.title)
end
def disable_answer?(question_answer)
def disable_answer?(question_option)
question.multiple? && user_answers.count == question.max_votes
end

View File

@@ -10,10 +10,10 @@
<% end %>
<div id="<%= dom_id(question) %>_answers" class="padding">
<%= render Polls::Questions::AnswersComponent.new(question) %>
<%= render Polls::Questions::OptionsComponent.new(question) %>
</div>
<% if question.answers_with_read_more? %>
<% if question.options_with_read_more? %>
<div>
<p><%= t("poll_questions.read_more_about") %></p>
<p><%= answers_read_more_links %></p>

View File

@@ -6,7 +6,7 @@ class Polls::Questions::QuestionComponent < ApplicationComponent
end
def answers_read_more_links
safe_join(question.answers_with_read_more.map do |answer|
safe_join(question.options_with_read_more.map do |answer|
link_to answer.title, "#answer_#{answer.id}"
end, ", ")
end

View File

@@ -1,5 +1,5 @@
<h2><%= question.title %></h2>
<% question.answers_with_read_more.each do |answer| %>
<% question.options_with_read_more.each do |answer| %>
<div class="small-12 medium-6 column end answer <%= cycle("first", "") %>" id="answer_<%= answer.id %>">
<h3><%= answer.title %></h3>

View File

@@ -8,6 +8,6 @@ class Polls::Questions::ReadMoreComponent < ApplicationComponent
end
def render?
question.answers_with_read_more?
question.options_with_read_more?
end
end

View File

@@ -2,7 +2,7 @@
<table id="question_<%= question.id %>_results_table">
<thead>
<tr>
<%- question.question_answers.each do |answer| %>
<%- question.question_options.each do |answer| %>
<th scope="col" class="<%= answer_styles(answer) %>">
<% if most_voted_answer?(answer) %>
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
@@ -14,7 +14,7 @@
</thead>
<tbody>
<tr>
<%- question.question_answers.each do |answer| %>
<%- question.question_options.each do |answer| %>
<td id="answer_<%= answer.id %>_result" class="<%= answer_styles(answer) %>">
<%= answer.total_votes %>
(<%= answer.total_votes_percentage.round(2) %>%)

View File

@@ -10,6 +10,6 @@ class Polls::Results::QuestionComponent < ApplicationComponent
end
def most_voted_answer?(answer)
answer.id == question.most_voted_answer_id
answer.id == question.most_voted_option_id
end
end

View File

@@ -1,30 +0,0 @@
class Admin::Poll::Questions::Answers::DocumentsController < Admin::Poll::BaseController
include DocumentAttributes
load_and_authorize_resource :answer, class: "::Poll::Question::Answer"
def index
end
def create
@answer.attributes = documents_params
authorize! :update, @answer
if @answer.save
redirect_to admin_answer_documents_path(@answer),
notice: t("admin.documents.create.success_notice")
else
render :index
end
end
private
def documents_params
params.require(:poll_question_answer).permit(allowed_params)
end
def allowed_params
[documents_attributes: document_attributes]
end
end

View File

@@ -1,41 +0,0 @@
class Admin::Poll::Questions::Answers::ImagesController < Admin::Poll::BaseController
include ImageAttributes
load_and_authorize_resource :answer, class: "::Poll::Question::Answer"
load_and_authorize_resource only: [:destroy]
def index
end
def new
end
def create
@answer.attributes = images_params
authorize! :update, @answer
if @answer.save
redirect_to admin_answer_images_path(@answer),
notice: t("flash.actions.create.poll_question_answer_image")
else
render :new
end
end
def destroy
@image.destroy!
redirect_to admin_answer_images_path(@image.imageable),
notice: t("flash.actions.destroy.poll_question_answer_image")
end
private
def images_params
params.require(:poll_question_answer).permit(allowed_params)
end
def allowed_params
[:answer_id, images_attributes: image_attributes]
end
end

View File

@@ -1,46 +0,0 @@
class Admin::Poll::Questions::Answers::VideosController < Admin::Poll::BaseController
load_and_authorize_resource :answer, class: "::Poll::Question::Answer"
load_and_authorize_resource class: "::Poll::Question::Answer::Video", through: :answer
def index
end
def new
end
def create
if @video.save
redirect_to admin_answer_videos_path(@answer),
notice: t("flash.actions.create.poll_question_answer_video")
else
render :new
end
end
def edit
end
def update
if @video.update(video_params)
redirect_to admin_answer_videos_path(@answer), notice: t("flash.actions.save_changes.notice")
else
render :edit
end
end
def destroy
@video.destroy!
notice = t("flash.actions.destroy.poll_question_answer_video")
redirect_to admin_answer_videos_path(@answer), notice: notice
end
private
def video_params
params.require(:poll_question_answer_video).permit(allowed_params)
end
def allowed_params
[:title, :url]
end
end

View File

@@ -0,0 +1,30 @@
class Admin::Poll::Questions::Options::DocumentsController < Admin::Poll::BaseController
include DocumentAttributes
load_and_authorize_resource :option, class: "::Poll::Question::Option"
def index
end
def create
@option.attributes = documents_params
authorize! :update, @option
if @option.save
redirect_to admin_option_documents_path(@option),
notice: t("admin.documents.create.success_notice")
else
render :index
end
end
private
def documents_params
params.require(:poll_question_option).permit(allowed_params)
end
def allowed_params
[documents_attributes: document_attributes]
end
end

View File

@@ -0,0 +1,41 @@
class Admin::Poll::Questions::Options::ImagesController < Admin::Poll::BaseController
include ImageAttributes
load_and_authorize_resource :option, class: "::Poll::Question::Option"
load_and_authorize_resource only: [:destroy]
def index
end
def new
end
def create
@option.attributes = images_params
authorize! :update, @option
if @option.save
redirect_to admin_option_images_path(@option),
notice: t("flash.actions.create.poll_question_option_image")
else
render :new
end
end
def destroy
@image.destroy!
redirect_to admin_option_images_path(@image.imageable),
notice: t("flash.actions.destroy.poll_question_option_image")
end
private
def images_params
params.require(:poll_question_option).permit(allowed_params)
end
def allowed_params
[:option_id, images_attributes: image_attributes]
end
end

View File

@@ -0,0 +1,46 @@
class Admin::Poll::Questions::Options::VideosController < Admin::Poll::BaseController
load_and_authorize_resource :option, class: "::Poll::Question::Option"
load_and_authorize_resource class: "::Poll::Question::Option::Video", through: :option
def index
end
def new
end
def create
if @video.save
redirect_to admin_option_videos_path(@option),
notice: t("flash.actions.create.poll_question_option_video")
else
render :new
end
end
def edit
end
def update
if @video.update(video_params)
redirect_to admin_option_videos_path(@option), notice: t("flash.actions.save_changes.notice")
else
render :edit
end
end
def destroy
@video.destroy!
notice = t("flash.actions.destroy.poll_question_option_video")
redirect_to admin_option_videos_path(@option), notice: notice
end
private
def video_params
params.require(:poll_question_option_video).permit(allowed_params)
end
def allowed_params
[:title, :url]
end
end

View File

@@ -1,18 +1,18 @@
class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
class Admin::Poll::Questions::OptionsController < Admin::Poll::BaseController
include Translatable
load_and_authorize_resource :question, class: "::Poll::Question"
load_and_authorize_resource class: "::Poll::Question::Answer",
load_and_authorize_resource class: "::Poll::Question::Option",
through: :question,
through_association: :question_answers
through_association: :question_options
def new
end
def create
if @answer.save
if @option.save
redirect_to admin_question_path(@question),
notice: t("flash.actions.create.poll_question_answer")
notice: t("flash.actions.create.poll_question_option")
else
render :new
end
@@ -22,7 +22,7 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
end
def update
if @answer.update(answer_params)
if @option.update(option_params)
redirect_to admin_question_path(@question),
notice: t("flash.actions.save_changes.notice")
else
@@ -31,24 +31,24 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
end
def destroy
@answer.destroy!
@option.destroy!
redirect_to admin_question_path(@question), notice: t("admin.answers.destroy.success_notice")
end
def order_answers
::Poll::Question::Answer.order_answers(params[:ordered_list])
def order_options
::Poll::Question::Option.order_options(params[:ordered_list])
head :ok
end
private
def answer_params
params.require(:poll_question_answer).permit(allowed_params)
def option_params
params.require(:poll_question_option).permit(allowed_params)
end
def allowed_params
attributes = [:title, :description, :given_order]
[*attributes, translation_params(Poll::Question::Answer)]
[*attributes, translation_params(Poll::Question::Option)]
end
end

View File

@@ -66,10 +66,10 @@ class Dashboard::PollsController < Dashboard::BaseController
def question_attributes
[:id, :title, :author_id, :proposal_id, :_destroy,
question_answers_attributes: question_answers_attributes]
question_options_attributes: question_options_attributes]
end
def question_answers_attributes
def question_options_attributes
[:id, :_destroy, :title, :description, :given_order, :question_id,
documents_attributes: document_attributes]
end

View File

@@ -43,7 +43,7 @@ class Officing::ResultsController < Officing::BaseController
results.each_pair do |answer_index, count|
next if count.blank?
answer = question.question_answers.find_by(given_order: answer_index.to_i + 1).title
answer = question.question_options.find_by(given_order: answer_index.to_i + 1).title
go_back_to_new if question.blank?
partial_result = ::Poll::PartialResult.find_or_initialize_by(

View File

@@ -12,7 +12,7 @@ class Polls::AnswersController < ApplicationController
redirect_to request.referer
end
format.js do
render "polls/questions/answers"
render "polls/questions/options"
end
end
end

View File

@@ -13,7 +13,7 @@ class Polls::QuestionsController < ApplicationController
redirect_to request.referer
end
format.js do
render :answers
render :options
end
end
end

View File

@@ -96,16 +96,16 @@ module Abilities
can [:update, :destroy], Poll::Question do |question|
!question.poll.started?
end
can [:read, :order_answers], Poll::Question::Answer
can [:create, :update, :destroy], Poll::Question::Answer do |answer|
can?(:update, answer.question)
can [:read, :order_options], Poll::Question::Option
can [:create, :update, :destroy], Poll::Question::Option do |option|
can?(:update, option.question)
end
can :read, Poll::Question::Answer::Video
can [:create, :update, :destroy], Poll::Question::Answer::Video do |video|
can?(:update, video.answer)
can :read, Poll::Question::Option::Video
can [:create, :update, :destroy], Poll::Question::Option::Video do |video|
can?(:update, video.option)
end
can [:destroy], Image do |image|
image.imageable_type == "Poll::Question::Answer" && can?(:update, image.imageable)
image.imageable_type == "Poll::Question::Option" && can?(:update, image.imageable)
end
can :manage, SiteCustomization::Page
@@ -127,7 +127,7 @@ module Abilities
can [:create], Document
can [:destroy], Document do |document|
document.documentable_type == "Poll::Question::Answer" && can?(:update, document.documentable)
document.documentable_type == "Poll::Question::Option" && can?(:update, document.documentable)
end
can [:create, :destroy], DirectUpload

View File

@@ -71,11 +71,11 @@ module Abilities
can [:create, :destroy], Follow, user_id: user.id
can [:destroy], Document do |document|
document.documentable_type != "Poll::Question::Answer" && document.documentable&.author_id == user.id
document.documentable_type != "Poll::Question::Option" && document.documentable&.author_id == user.id
end
can [:destroy], Image do |image|
image.imageable_type != "Poll::Question::Answer" && image.imageable&.author_id == user.id
image.imageable_type != "Poll::Question::Option" && image.imageable&.author_id == user.id
end
can [:create, :destroy], DirectUpload

View File

@@ -14,8 +14,8 @@ class Poll::Question < ApplicationRecord
has_many :comments, as: :commentable, inverse_of: :commentable
has_many :answers, class_name: "Poll::Answer"
has_many :question_answers, -> { order "given_order asc" },
class_name: "Poll::Question::Answer",
has_many :question_options, -> { order "given_order asc" },
class_name: "Poll::Question::Option",
inverse_of: :question,
dependent: :destroy
has_many :partial_results
@@ -25,7 +25,7 @@ class Poll::Question < ApplicationRecord
validates :author, presence: true
validates :poll_id, presence: true, if: proc { |question| question.poll.nil? }
accepts_nested_attributes_for :question_answers, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :question_options, reject_if: :all_blank, allow_destroy: true
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
@@ -63,23 +63,23 @@ class Poll::Question < ApplicationRecord
where(poll_id: Poll.answerable_by(user).pluck(:id))
end
def answers_total_votes
question_answers.reduce(0) { |total, question_answer| total + question_answer.total_votes }
def options_total_votes
question_options.reduce(0) { |total, question_option| total + question_option.total_votes }
end
def most_voted_answer_id
question_answers.max_by(&:total_votes)&.id
def most_voted_option_id
question_options.max_by(&:total_votes)&.id
end
def possible_answers
question_answers.joins(:translations).pluck(:title)
question_options.joins(:translations).pluck(:title)
end
def answers_with_read_more?
answers_with_read_more.any?
def options_with_read_more?
options_with_read_more.any?
end
def answers_with_read_more
question_answers.select(&:with_read_more?)
def options_with_read_more
question_options.select(&:with_read_more?)
end
end

View File

@@ -1,6 +0,0 @@
class Poll::Question::Answer::Video < ApplicationRecord
belongs_to :answer, class_name: "Poll::Question::Answer"
include Videoable
validates :title, presence: true
end

View File

@@ -1,4 +1,6 @@
class Poll::Question::Answer < ApplicationRecord
class Poll::Question::Option < ApplicationRecord
self.table_name = "poll_question_answers"
include Galleryable
include Documentable
@@ -9,7 +11,10 @@ class Poll::Question::Answer < ApplicationRecord
accepts_nested_attributes_for :documents, allow_destroy: true
belongs_to :question, class_name: "Poll::Question"
has_many :videos, class_name: "Poll::Question::Answer::Video", dependent: :destroy
has_many :videos, class_name: "Poll::Question::Option::Video",
dependent: :destroy,
foreign_key: "answer_id",
inverse_of: :option
validates_translation :title, presence: true
validates :given_order, presence: true, uniqueness: { scope: :question_id }
@@ -22,9 +27,9 @@ class Poll::Question::Answer < ApplicationRecord
.where.missing(:videos)
end
def self.order_answers(ordered_array)
ordered_array.each_with_index do |answer_id, order|
find(answer_id).update_column(:given_order, (order + 1))
def self.order_options(ordered_array)
ordered_array.each_with_index do |option_id, order|
find(option_id).update_column(:given_order, (order + 1))
end
end
@@ -38,7 +43,7 @@ class Poll::Question::Answer < ApplicationRecord
end
def total_votes_percentage
question.answers_total_votes.zero? ? 0 : (total_votes * 100.0) / question.answers_total_votes
question.options_total_votes.zero? ? 0 : (total_votes * 100.0) / question.options_total_votes
end
def with_read_more?

View File

@@ -0,0 +1,6 @@
class Poll::Question::Option::Video < ApplicationRecord
belongs_to :option, class_name: "Poll::Question::Option", foreign_key: "answer_id", inverse_of: :videos
include Videoable
validates :title, presence: true
end

View File

@@ -1 +0,0 @@
<%= render Admin::Poll::Questions::Answers::Documents::IndexComponent.new(@answer) %>

View File

@@ -1,9 +0,0 @@
<%= back_link_to admin_answer_videos_path(@answer) %>
<h2>
<%= t("admin.answers.videos.new.title") %>
</h2>
<div class="poll-question-answer-video-form">
<%= render "form", form_url: admin_answer_videos_path(@answer) %>
</div>

View File

@@ -1,11 +1,11 @@
<%= render "shared/globalize_locales", resource: @answer %>
<%= render "shared/globalize_locales", resource: @option %>
<%= translatable_form_for(@answer, url: form_url) do |f| %>
<%= translatable_form_for(@option, url: form_url) do |f| %>
<%= render "shared/errors", resource: @answer %>
<%= render "shared/errors", resource: @option %>
<%= f.hidden_field :given_order,
value: @answer.persisted? ? @answer.given_order : @answer.class.last_position(@answer.question_id || @question.id) + 1 %>
value: @option.persisted? ? @option.given_order : @option.class.last_position(@option.question_id || @question.id) + 1 %>
<div class="row">
<%= f.translatable_fields do |translations_form| %>

View File

@@ -0,0 +1 @@
<%= render Admin::Poll::Questions::Options::Documents::IndexComponent.new(@option) %>

View File

@@ -1,7 +1,7 @@
<%= back_link_to admin_question_path(@question) %>
<ul class="breadcrumbs margin-top">
<li><%= @answer.title %></li>
<li><%= @option.title %></li>
<li><%= t("admin.answers.edit.title") %></li>
</ul>
@@ -10,5 +10,5 @@
</h2>
<div class="poll-question-answer-form">
<%= render "form", form_url: admin_question_answer_path(@question, @answer) %>
<%= render "form", form_url: admin_question_option_path(@question, @option) %>
</div>

View File

@@ -1,4 +1,4 @@
<%= back_link_to admin_question_path(@answer.question) %>
<%= back_link_to admin_question_path(@option.question) %>
<div class="clear"></div>
@@ -6,9 +6,9 @@
<%= t("admin.answers.images.index.title") %>
</h2>
<% if can?(:update, @answer) %>
<% if can?(:update, @option) %>
<%= link_to t("admin.questions.answers.images.add_image"),
new_admin_answer_image_path(@answer),
new_admin_option_image_path(@option),
class: "button hollow float-right" %>
<% else %>
<div class="callout warning">
@@ -17,11 +17,11 @@
<% end %>
<ul class="breadcrumbs margin-top">
<li><%= @answer.question.title %></li>
<li><%= @answer.title %></li>
<li><%= @option.question.title %></li>
<li><%= @option.title %></li>
</ul>
<% @answer.images.each do |image| %>
<% @option.images.each do |image| %>
<div class="small-12 medium-4 column end">
<%= render_image(image, :large, true) if image.present? %>

View File

@@ -1,6 +1,6 @@
<div class="poll-question-form">
<%= form_for(@answer, url: admin_answer_images_path(@answer), method: :post) do |f| %>
<%= render "shared/errors", resource: @answer %>
<%= form_for(@option, url: admin_option_images_path(@option), method: :post) do |f| %>
<%= render "shared/errors", resource: @option %>
<%= render Images::NestedComponent.new(f, image_fields: :images) %>

View File

@@ -8,5 +8,5 @@
<h2><%= t("admin.answers.new.title") %></h2>
<div class="poll-question-answer-form">
<%= render "form", form_url: admin_question_answers_path %>
<%= render "form", form_url: admin_question_options_path %>
</div>

View File

@@ -1,9 +1,9 @@
<%= back_link_to admin_answer_videos_path(@answer) %>
<%= back_link_to admin_option_videos_path(@option) %>
<h2>
<%= t("admin.answers.videos.edit.title") %>
</h2>
<div class="poll-question-answer-video-form">
<%= render "form", form_url: admin_answer_video_path(@answer, @video) %>
<%= render "form", form_url: admin_option_video_path(@option, @video) %>
</div>

View File

@@ -1,4 +1,4 @@
<%= back_link_to admin_question_path(@answer.question) %>
<%= back_link_to admin_question_path(@option.question) %>
<div class="clear"></div>
@@ -6,9 +6,9 @@
<%= t("admin.answers.videos.index.title") %>
</h2>
<% if can?(:create, Poll::Question::Answer.new(question: @answer.question)) %>
<% if can?(:create, Poll::Question::Option.new(question: @option.question)) %>
<%= link_to t("admin.answers.videos.index.add_video"),
new_admin_answer_video_path(@answer),
new_admin_option_video_path(@option),
class: "button success float-right" %>
<% else %>
<div class="callout warning">
@@ -33,7 +33,7 @@
<td><%= video.title %></td>
<td><%= link_to video.url, video.url %></td>
<td>
<%= render Admin::Poll::Questions::Answers::Videos::TableActionsComponent.new(video) %>
<%= render Admin::Poll::Questions::Options::Videos::TableActionsComponent.new(video) %>
</td>
</tr>
<% end %>

View File

@@ -0,0 +1,9 @@
<%= back_link_to admin_option_videos_path(@option) %>
<h2>
<%= t("admin.answers.videos.new.title") %>
</h2>
<div class="poll-question-answer-video-form">
<%= render "form", form_url: admin_option_videos_path(@option) %>
</div>

View File

@@ -47,8 +47,8 @@
</div>
<div class="clear">
<% if can?(:create, Poll::Question::Answer.new(question: @question)) %>
<%= link_to t("admin.questions.show.add_answer"), new_admin_question_answer_path(@question),
<% if can?(:create, Poll::Question::Option.new(question: @question)) %>
<%= link_to t("admin.questions.show.add_answer"), new_admin_question_option_path(@question),
class: "button float-right" %>
<% else %>
<div class="callout warning">
@@ -70,8 +70,8 @@
</tr>
</thead>
<tbody class="sortable" data-js-url="<%= admin_question_answers_order_answers_path(@question.id) %>">
<% @question.question_answers.each do |answer| %>
<tbody class="sortable" data-js-url="<%= admin_question_options_order_options_path(@question.id) %>">
<% @question.question_options.each do |answer| %>
<tr id="<%= dom_id(answer) %>" class="poll_question_answer" data-answer-id="<%= answer.id %>">
<td class="align-top"><%= answer.title %></td>
<td class="align-top break"><%= wysiwyg(answer.description) %></td>
@@ -79,22 +79,22 @@
(<%= answer.images.count %>)
<br>
<%= link_to t("admin.questions.show.answers.images_list"),
admin_answer_images_path(answer) %>
admin_option_images_path(answer) %>
</td>
<td class="align-top text-center">
(<%= answer.documents.count rescue 0 %>)
<br>
<%= link_to t("admin.questions.show.answers.documents_list"),
admin_answer_documents_path(answer) %>
admin_option_documents_path(answer) %>
</td>
<td class="align-top text-center">
(<%= answer.videos.count %>)
<br>
<%= link_to t("admin.questions.show.answers.video_list"),
admin_answer_videos_path(answer) %>
admin_option_videos_path(answer) %>
</td>
<td>
<%= render Admin::Poll::Questions::Answers::TableActionsComponent.new(answer) %>
<%= render Admin::Poll::Questions::Options::TableActionsComponent.new(answer) %>
</td>
</tr>
<% end %>

View File

@@ -9,11 +9,11 @@
</tr>
</thead>
<tbody>
<% question.question_answers.each_with_index do |answer, i| %>
<% question.question_options.each_with_index do |option, i| %>
<% by_answer = by_question[question.id].present? ? by_question[question.id].group_by(&:answer) : {} %>
<tr id="question_<%= question.id %>_<%= i %>_result">
<td><%= answer.title %></td>
<td class="text-center"><%= by_answer[answer.title].present? ? by_answer[answer.title].sum(&:amount) : 0 %></td>
<td><%= option.title %></td>
<td class="text-center"><%= by_answer[option.title].present? ? by_answer[option.title].sum(&:amount) : 0 %></td>
</tr>
<% end %>
</tbody>

View File

@@ -13,14 +13,14 @@
</div>
<div class="js-answers">
<%= f.fields_for :question_answers do |answer| %>
<%= render "question_answer_fields", f: answer %>
<%= f.fields_for :question_options do |answer| %>
<%= render "question_option_fields", f: answer %>
<% end %>
<div class="answer-links links row expanded">
<div class="small-12 column">
<%= link_to_add_association t("dashboard.polls.question_fields.add_answer"),
f, :question_answers, class: "button hollow" %>
f, :question_options, class: "button hollow" %>
</div>
</div>
</div>

View File

@@ -39,11 +39,11 @@
</tr>
</thead>
<tbody>
<% question.question_answers.each_with_index do |answer, i| %>
<% question.question_options.each_with_index do |option, i| %>
<% by_answer = by_question[question.id].present? ? by_question[question.id].group_by(&:answer) : {} %>
<tr id="question_<%= question.id %>_<%= i %>_result">
<td><%= answer.title %></td>
<td><%= by_answer[answer.title].present? ? by_answer[answer.title].first.amount : 0 %></td>
<td><%= option.title %></td>
<td><%= by_answer[option.title].present? ? by_answer[option.title].first.amount : 0 %></td>
</tr>
<% end %>
</tbody>

View File

@@ -16,7 +16,7 @@
<div class="small-12 column">
<h3><%= question.title %></h3>
</div>
<% question.question_answers.each_with_index do |answer, i| %>
<% question.question_options.each_with_index do |answer, i| %>
<div class="small-12 medium-6 large-3 column end">
<label><%= answer.title %></label>
<%= text_field_tag "questions[#{question.id}][#{i}]", answer_result_value(question.id, i), placeholder: "0" %>

View File

@@ -1 +1 @@
$("#<%= dom_id(@question) %>_answers").html("<%= j render Polls::Questions::AnswersComponent.new(@question) %>");
$("#<%= dom_id(@question) %>_answers").html("<%= j render Polls::Questions::OptionsComponent.new(@question) %>");

View File

@@ -25,8 +25,8 @@ module ActionDispatch::Routing::UrlFor
def namespaced_polymorphic_path(namespace, resource, options = {})
if %w[Budget::Group Budget::Heading Legislation::DraftVersion Legislation::Question
Poll::Booth Poll::BoothAssignment Poll::Officer Poll::Question Poll::Question::Answer
Poll::Question::Answer::Video Poll::Shift SDG::LocalTarget].include?(resource.class.name)
Poll::Booth Poll::BoothAssignment Poll::Officer Poll::Question Poll::Question::Option
Poll::Question::Option::Video Poll::Shift SDG::LocalTarget].include?(resource.class.name)
resolve = resolve_for(resource)
resolve_options = resolve.pop

View File

@@ -459,13 +459,13 @@ en:
image:
title: Title
attachment: "Choose image"
poll/question/answer:
poll/question/option:
title: Answer
description: Description
poll/question/answer/translation:
poll/question/option/translation:
title: Answer
description: "Description (optional)"
poll/question/answer/video:
poll/question/option/video:
title: Title
url: External video
newsletter:

View File

@@ -162,7 +162,7 @@ en:
legislation/process: process
legislation/question: question
poll/shift: Shift
poll/question/answer: Answer
poll/question/option: Answer
user: Account
verification/sms: phone
signature_sheet: Signature sheet

View File

@@ -7,9 +7,9 @@ en:
direct_message: "You message has been sent successfully."
poll: "Poll created successfully."
poll_booth: "Booth created successfully."
poll_question_answer: "Answer created successfully"
poll_question_answer_video: "Video created successfully"
poll_question_answer_image: "Image uploaded successfully"
poll_question_option: "Answer created successfully"
poll_question_option_video: "Video created successfully"
poll_question_option_image: "Image uploaded successfully"
proposal: "Proposal created successfully."
proposal_notification: "Your message has been sent correctly."
budget_investment: "Budget Investment created successfully."
@@ -34,7 +34,7 @@ en:
destroy:
budget_investment: "Investment project deleted successfully."
topic: "Topic deleted successfully."
poll_question_answer_image: "Image deleted successfully."
poll_question_answer_video: "Answer video deleted successfully."
poll_question_option_image: "Image deleted successfully."
poll_question_option_video: "Answer video deleted successfully."
valuator_group: "Valuator group deleted successfully"
vote: "Vote deleted successfully"

View File

@@ -459,13 +459,13 @@ es:
image:
title: Título
attachment: "Selecciona una imagen"
poll/question/answer:
poll/question/option:
title: Respuesta
description: Descripción
poll/question/answer/translation:
poll/question/option/translation:
title: Respuesta
description: "Descripción (opcional)"
poll/question/answer/video:
poll/question/option/video:
title: Título
url: Vídeo externo
newsletter:

View File

@@ -162,7 +162,7 @@ es:
legislation/process: el proceso
legislation/question: la pregunta
poll/shift: el turno
poll/question/answer: la respuesta
poll/question/option: la respuesta
user: la cuenta
verification/sms: el teléfono
signature_sheet: la hoja de firmas

View File

@@ -7,9 +7,9 @@ es:
direct_message: "Tu mensaje ha sido enviado correctamente."
poll: "Votación creada correctamente."
poll_booth: "Urna creada correctamente."
poll_question_answer: "Respuesta creada correctamente"
poll_question_answer_video: "Vídeo creado correctamente"
poll_question_answer_image: "Imagen cargada correctamente"
poll_question_option: "Respuesta creada correctamente"
poll_question_option_video: "Vídeo creado correctamente"
poll_question_option_image: "Imagen cargada correctamente"
proposal: "Propuesta creada correctamente."
proposal_notification: "Tu mensaje ha sido enviado correctamente."
budget_investment: "Proyecto de gasto creado correctamente."
@@ -34,7 +34,7 @@ es:
destroy:
budget_investment: "Proyecto de gasto eliminado."
topic: "Tema eliminado."
poll_question_answer_image: "Imagen eliminada correctamente."
poll_question_answer_video: "Vídeo de respuesta eliminado."
poll_question_option_image: "Imagen eliminada correctamente."
poll_question_option_video: "Vídeo de respuesta eliminado."
valuator_group: "Grupo de evaluadores eliminado correctamente"
vote: "Voto eliminado correctamente"

View File

@@ -175,13 +175,13 @@ namespace :admin do
end
resources :questions, shallow: true do
resources :answers, except: [:index, :show], controller: "questions/answers", shallow: false
resources :answers, only: [], controller: "questions/answers" do
resources :images, controller: "questions/answers/images"
resources :videos, controller: "questions/answers/videos", shallow: false
resources :documents, only: [:index, :create], controller: "questions/answers/documents"
resources :options, except: [:index, :show], controller: "questions/options", shallow: false
resources :options, only: [], controller: "questions/options" do
resources :images, controller: "questions/options/images"
resources :videos, controller: "questions/options/videos", shallow: false
resources :documents, only: [:index, :create], controller: "questions/options/documents"
end
post "/answers/order_answers", to: "questions/answers#order_answers"
post "/options/order_options", to: "questions/options#order_options"
end
resource :active_polls, only: [:create, :edit, :update]
@@ -336,12 +336,12 @@ resolve "Poll::Officer" do |officer, options|
[:officer, options.merge(id: officer)]
end
resolve "Poll::Question::Answer" do |answer, options|
[:question, :answer, options.merge(question_id: answer.question, id: answer)]
resolve "Poll::Question::Option" do |option, options|
[:question, :option, options.merge(question_id: option.question, id: option)]
end
resolve "Poll::Question::Answer::Video" do |video, options|
[:answer, :video, options.merge(answer_id: video.answer, id: video)]
resolve "Poll::Question::Option::Video" do |video, options|
[:option, :video, options.merge(option_id: video.option, id: video)]
end
resolve "Legislation::DraftVersion" do |version, options|

View File

@@ -64,17 +64,17 @@ section "Creating Poll Questions & Answers" do
question.save!
Faker::Lorem.words(number: (2..4).to_a.sample).each_with_index do |title, index|
description = "<p>#{Faker::Lorem.paragraphs.join("</p><p>")}</p>"
answer = Poll::Question::Answer.new(question: question,
option = Poll::Question::Option.new(question: question,
title: title.capitalize,
description: description,
given_order: index + 1)
Setting.enabled_locales.map do |locale|
Globalize.with_locale(locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
option.title = "#{title} (#{locale})"
option.description = "#{description} (#{locale})"
end
end
answer.save!
option.save!
end
end
end
@@ -160,7 +160,7 @@ section "Creating Poll Voters" do
Poll::Answer.create!(question_id: question.id,
author: user,
answer: question.question_answers.sample.title)
answer: question.question_options.sample.title)
end
end
@@ -210,7 +210,7 @@ section "Creating Poll Results" do
author = Poll::Officer.first.user
poll.questions.each do |question|
question.question_answers.each do |answer|
question.question_options.each do |answer|
Poll::PartialResult.create!(officer_assignment: officer_assignment,
booth_assignment: booth_assignment,
date: Date.current,
@@ -240,17 +240,17 @@ section "Creating Poll Questions from Proposals" do
question.save!
Faker::Lorem.words(number: (2..4).to_a.sample).each_with_index do |title, index|
description = "<p>#{Faker::ChuckNorris.fact}</p>"
answer = Poll::Question::Answer.new(question: question,
option = Poll::Question::Option.new(question: question,
title: title.capitalize,
description: description,
given_order: index + 1)
Setting.enabled_locales.map do |locale|
Globalize.with_locale(locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
option.title = "#{title} (#{locale})"
option.description = "#{description} (#{locale})"
end
end
answer.save!
option.save!
end
end
end
@@ -270,17 +270,17 @@ section "Creating Successful Proposals" do
question.save!
Faker::Lorem.words(number: (2..4).to_a.sample).each_with_index do |title, index|
description = "<p>#{Faker::ChuckNorris.fact}</p>"
answer = Poll::Question::Answer.new(question: question,
option = Poll::Question::Option.new(question: question,
title: title.capitalize,
description: description,
given_order: index + 1)
Setting.enabled_locales.map do |locale|
Globalize.with_locale(locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
option.title = "#{title} (#{locale})"
option.description = "#{description} (#{locale})"
end
end
answer.save!
option.save!
end
end
end

View File

@@ -19,4 +19,20 @@ describe Admin::MenuComponent, controller: Admin::NewslettersController do
expect(page).to have_css "button[aria-expanded='false']", exact_text: "Settings"
end
describe "#polls_link" do
it "is marked as current when managing poll options",
controller: Admin::Poll::Questions::OptionsController do
render_inline Admin::MenuComponent.new
expect(page).to have_css "[aria-current]", exact_text: "Polls"
end
it "is marked as current when managing poll options content",
controller: Admin::Poll::Questions::Options::VideosController do
render_inline Admin::MenuComponent.new
expect(page).to have_css "[aria-current]", exact_text: "Polls"
end
end
end

View File

@@ -1,18 +1,18 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::Documents::IndexComponent do
describe Admin::Poll::Questions::Options::Documents::IndexComponent do
before { sign_in(create(:administrator).user) }
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_option, poll: create(:poll, :future)) }
let(:current_answer) { create(:poll_question_option, poll: create(:poll)) }
it "displays the 'Add new document' link when the poll has not started" do
render_inline Admin::Poll::Questions::Answers::Documents::IndexComponent.new(future_answer)
render_inline Admin::Poll::Questions::Options::Documents::IndexComponent.new(future_answer)
expect(page).to have_link "Add new document"
end
it "does not display the 'Add new document' link when the poll has started" do
render_inline Admin::Poll::Questions::Answers::Documents::IndexComponent.new(current_answer)
render_inline Admin::Poll::Questions::Options::Documents::IndexComponent.new(current_answer)
expect(page).not_to have_link "Add new document"
end

View File

@@ -1,13 +1,13 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::Documents::TableActionsComponent, :admin do
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
describe Admin::Poll::Questions::Options::Documents::TableActionsComponent, :admin do
let(:future_answer) { create(:poll_question_option, poll: create(:poll, :future)) }
let(:current_answer) { create(:poll_question_option, poll: create(:poll)) }
it "displays the destroy action when the poll has not started" do
document = create(:document, documentable: future_answer)
render_inline Admin::Poll::Questions::Answers::Documents::TableActionsComponent.new(document)
render_inline Admin::Poll::Questions::Options::Documents::TableActionsComponent.new(document)
expect(page).to have_link "Download file"
expect(page).to have_button "Delete"
@@ -17,7 +17,7 @@ describe Admin::Poll::Questions::Answers::Documents::TableActionsComponent, :adm
it "does not display the destroy action when the poll has started" do
document = create(:document, documentable: current_answer)
render_inline Admin::Poll::Questions::Answers::Documents::TableActionsComponent.new(document)
render_inline Admin::Poll::Questions::Options::Documents::TableActionsComponent.new(document)
expect(page).to have_link "Download file"
expect(page).not_to have_button "Delete"

View File

@@ -1,19 +1,19 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::TableActionsComponent, :admin do
describe Admin::Poll::Questions::Options::TableActionsComponent, :admin do
it "displays the edit and destroy actions when the poll has not started" do
answer = create(:poll_question_answer, poll: create(:poll, :future))
option = create(:poll_question_option, poll: create(:poll, :future))
render_inline Admin::Poll::Questions::Answers::TableActionsComponent.new(answer)
render_inline Admin::Poll::Questions::Options::TableActionsComponent.new(option)
expect(page).to have_link "Edit"
expect(page).to have_button "Delete"
end
it "does not display the edit and destroy actions when the poll has started" do
answer = create(:poll_question_answer, poll: create(:poll))
option = create(:poll_question_option, poll: create(:poll))
render_inline Admin::Poll::Questions::Answers::TableActionsComponent.new(answer)
render_inline Admin::Poll::Questions::Options::TableActionsComponent.new(option)
expect(page).not_to have_link "Edit"
expect(page).not_to have_button "Delete"

View File

@@ -1,19 +1,19 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::Videos::TableActionsComponent, :admin do
describe Admin::Poll::Questions::Options::Videos::TableActionsComponent, :admin do
it "displays the edit and destroy actions when the poll has not started" do
video = create(:poll_answer_video, poll: create(:poll, :future))
video = create(:poll_option_video, poll: create(:poll, :future))
render_inline Admin::Poll::Questions::Answers::Videos::TableActionsComponent.new(video)
render_inline Admin::Poll::Questions::Options::Videos::TableActionsComponent.new(video)
expect(page).to have_link "Edit"
expect(page).to have_button "Delete"
end
it "does not display the edit and destroy actions when the poll has started" do
video = create(:poll_answer_video, poll: create(:poll))
video = create(:poll_option_video, poll: create(:poll))
render_inline Admin::Poll::Questions::Answers::Videos::TableActionsComponent.new(video)
render_inline Admin::Poll::Questions::Options::Videos::TableActionsComponent.new(video)
expect(page).not_to have_link "Edit"
expect(page).not_to have_button "Delete"

View File

@@ -1,12 +1,12 @@
require "rails_helper"
describe Polls::Questions::AnswersComponent do
describe Polls::Questions::OptionsComponent do
include Rails.application.routes.url_helpers
let(:poll) { create(:poll) }
let(:question) { create(:poll_question, :yes_no, poll: poll) }
it "renders answers in given order" do
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect("Yes").to appear_before("No")
end
@@ -14,7 +14,7 @@ describe Polls::Questions::AnswersComponent do
it "renders buttons to vote question answers" do
sign_in(create(:user, :verified))
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_button "Yes"
expect(page).to have_button "No"
@@ -26,7 +26,7 @@ describe Polls::Questions::AnswersComponent do
create(:poll_answer, author: user, question: question, answer: "Yes")
sign_in(user)
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_button "You have voted Yes"
expect(page).to have_button "Vote No"
@@ -40,7 +40,7 @@ describe Polls::Questions::AnswersComponent do
create(:poll_answer, author: user, question: question, answer: "Answer C")
sign_in(user)
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_button "You have voted Answer A"
expect(page).to have_button "Vote Answer B", disabled: true
@@ -48,7 +48,7 @@ describe Polls::Questions::AnswersComponent do
end
it "when user is not signed in, renders answers links pointing to user sign in path" do
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_link "Yes", href: new_user_session_path
expect(page).to have_link "No", href: new_user_session_path
@@ -57,7 +57,7 @@ describe Polls::Questions::AnswersComponent do
it "when user is not verified, renders answers links pointing to user verification in path" do
sign_in(create(:user))
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_link "Yes", href: verification_path
expect(page).to have_link "No", href: verification_path
@@ -68,7 +68,7 @@ describe Polls::Questions::AnswersComponent do
create(:poll_voter, :from_booth, poll: poll, user: user)
sign_in(user)
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_css "span.disabled", text: "Yes"
expect(page).to have_css "span.disabled", text: "No"
@@ -78,7 +78,7 @@ describe Polls::Questions::AnswersComponent do
question = create(:poll_question, :yes_no, poll: create(:poll, :expired))
sign_in(create(:user, :level_two))
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_css "span.disabled", text: "Yes"
expect(page).to have_css "span.disabled", text: "No"
@@ -93,7 +93,7 @@ describe Polls::Questions::AnswersComponent do
poll.geozones << geozone
sign_in(create(:user, :level_two))
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_css "span.disabled", text: "Yes"
expect(page).to have_css "span.disabled", text: "No"
@@ -103,7 +103,7 @@ describe Polls::Questions::AnswersComponent do
poll.geozones << geozone
sign_in(create(:user, :level_two, geozone: geozone))
render_inline Polls::Questions::AnswersComponent.new(question)
render_inline Polls::Questions::OptionsComponent.new(question)
expect(page).to have_button "Yes"
expect(page).to have_button "No"

View File

@@ -3,9 +3,9 @@ require "rails_helper"
describe Polls::Questions::QuestionComponent do
it "renders more information links when any question answer has additional information" do
question = create(:poll_question)
answer_a = create(:poll_question_answer, question: question, title: "Answer A")
answer_b = create(:poll_question_answer, question: question, title: "Answer B")
allow_any_instance_of(Poll::Question::Answer).to receive(:with_read_more?).and_return(true)
answer_a = create(:poll_question_option, question: question, title: "Answer A")
answer_b = create(:poll_question_option, question: question, title: "Answer B")
allow_any_instance_of(Poll::Question::Option).to receive(:with_read_more?).and_return(true)
render_inline Polls::Questions::QuestionComponent.new(question: question)

View File

@@ -4,51 +4,51 @@ describe Polls::Questions::ReadMoreComponent do
include Rails.application.routes.url_helpers
let(:poll) { create(:poll) }
let(:question) { create(:poll_question, poll: poll, title: "Question title?") }
let(:answer) { create(:poll_question_answer, question: question) }
let(:option) { create(:poll_question_option, question: question) }
it "renders question title" do
create(:poll_question_answer, question: question, description: "Question answer description")
create(:poll_question_option, question: question, description: "Question option description")
render_inline Polls::Questions::ReadMoreComponent.new(question: question)
expect(page).to have_content "Question title?"
end
it "renders answers in the given order" do
create(:poll_question_answer, title: "Answer A", question: question, given_order: 2)
create(:poll_question_answer, title: "Answer B", question: question, given_order: 1)
it "renders options in the given order" do
create(:poll_question_option, title: "Answer A", question: question, given_order: 2)
create(:poll_question_option, title: "Answer B", question: question, given_order: 1)
render_inline Polls::Questions::ReadMoreComponent.new(question: question)
expect("Answer B").to appear_before("Answer A")
end
it "does not render when answers does not have more information" do
answer.update!(description: nil)
it "does not render when options does not have more information" do
option.update!(description: nil)
render_inline Polls::Questions::ReadMoreComponent.new(question: question)
expect(page).not_to be_rendered
end
it "renders answers with videos" do
create(:poll_answer_video, answer: answer, title: "Awesome video", url: "youtube.com/watch?v=123")
it "renders options with videos" do
create(:poll_option_video, option: option, title: "Awesome video", url: "youtube.com/watch?v=123")
render_inline Polls::Questions::ReadMoreComponent.new(question: question)
expect(page).to have_link("Awesome video", href: "youtube.com/watch?v=123")
end
it "renders answers with images" do
create(:image, imageable: answer, title: "The yes movement")
it "renders options with images" do
create(:image, imageable: option, title: "The yes movement")
render_inline Polls::Questions::ReadMoreComponent.new(question: question)
expect(page).to have_css "img[alt='The yes movement']"
end
it "renders answers with documents" do
create(:document, documentable: answer, title: "The yes movement")
it "renders options with documents" do
create(:document, documentable: option, title: "The yes movement")
render_inline Polls::Questions::ReadMoreComponent.new(question: question)

View File

@@ -1,11 +1,11 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::DocumentsController, :admin do
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
describe Admin::Poll::Questions::Options::DocumentsController, :admin do
let(:current_option) { create(:poll_question_option, poll: create(:poll)) }
let(:future_option) { create(:poll_question_option, poll: create(:poll, :future)) }
describe "POST create" do
let(:answer_attributes) do
let(:option_attributes) do
{
documents_attributes: {
"0" => {
@@ -18,16 +18,16 @@ describe Admin::Poll::Questions::Answers::DocumentsController, :admin do
end
it "is not possible for an already started poll" do
post :create, params: { poll_question_answer: answer_attributes, answer_id: current_answer }
post :create, params: { poll_question_option: option_attributes, option_id: current_option }
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Answer."
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Option."
expect(Document.count).to eq 0
end
it "is possible for a not started poll" do
post :create, params: { poll_question_answer: answer_attributes, answer_id: future_answer }
post :create, params: { poll_question_option: option_attributes, option_id: future_option }
expect(response).to redirect_to admin_answer_documents_path(future_answer)
expect(response).to redirect_to admin_option_documents_path(future_option)
expect(flash[:notice]).to eq "Document uploaded successfully"
expect(Document.count).to eq 1
end

View File

@@ -1,11 +1,11 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::ImagesController, :admin do
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
describe Admin::Poll::Questions::Options::ImagesController, :admin do
let(:current_option) { create(:poll_question_option, poll: create(:poll)) }
let(:future_option) { create(:poll_question_option, poll: create(:poll, :future)) }
describe "POST create" do
let(:answer_attributes) do
let(:option_attributes) do
{
images_attributes: {
"0" => {
@@ -18,16 +18,16 @@ describe Admin::Poll::Questions::Answers::ImagesController, :admin do
end
it "is not possible for an already started poll" do
post :create, params: { poll_question_answer: answer_attributes, answer_id: current_answer }
post :create, params: { poll_question_option: option_attributes, option_id: current_option }
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Answer."
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Option."
expect(Image.count).to eq 0
end
it "is possible for a not started poll" do
post :create, params: { poll_question_answer: answer_attributes, answer_id: future_answer }
post :create, params: { poll_question_option: option_attributes, option_id: future_option }
expect(response).to redirect_to admin_answer_images_path(future_answer)
expect(response).to redirect_to admin_option_images_path(future_option)
expect(flash[:notice]).to eq "Image uploaded successfully"
expect(Image.count).to eq 1
end
@@ -35,7 +35,7 @@ describe Admin::Poll::Questions::Answers::ImagesController, :admin do
describe "DELETE destroy" do
it "is not possible for an already started poll" do
current_image = create(:image, imageable: current_answer)
current_image = create(:image, imageable: current_option)
delete :destroy, xhr: true, params: { id: current_image }
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'destroy' on Image."
@@ -43,7 +43,7 @@ describe Admin::Poll::Questions::Answers::ImagesController, :admin do
end
it "is possible for a not started poll" do
future_image = create(:image, imageable: future_answer)
future_image = create(:image, imageable: future_option)
delete :destroy, xhr: true, params: { id: future_image }
expect(Image.count).to eq 0

View File

@@ -1,48 +1,48 @@
require "rails_helper"
describe Admin::Poll::Questions::Answers::VideosController, :admin do
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
describe Admin::Poll::Questions::Options::VideosController, :admin do
let(:current_option) { create(:poll_question_option, poll: create(:poll)) }
let(:future_option) { create(:poll_question_option, poll: create(:poll, :future)) }
describe "POST create" do
it "is not possible for an already started poll" do
post :create, params: {
poll_question_answer_video: {
poll_question_option_video: {
title: "Video from started poll",
url: "https://www.youtube.com/watch?v=-JMf43st-1A"
},
answer_id: current_answer
option_id: current_option
}
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'create' on Video."
expect(Poll::Question::Answer::Video.count).to eq 0
expect(Poll::Question::Option::Video.count).to eq 0
end
it "is possible for a not started poll" do
post :create, params: {
poll_question_answer_video: {
poll_question_option_video: {
title: "Video from not started poll",
url: "https://www.youtube.com/watch?v=-JMf43st-1A"
},
answer_id: future_answer
option_id: future_option
}
expect(response).to redirect_to admin_answer_videos_path(future_answer)
expect(response).to redirect_to admin_option_videos_path(future_option)
expect(flash[:notice]).to eq "Video created successfully"
expect(Poll::Question::Answer::Video.count).to eq 1
expect(Poll::Question::Option::Video.count).to eq 1
end
end
describe "PATCH update" do
it "is not possible for an already started poll" do
current_video = create(:poll_answer_video, answer: current_answer, title: "Sample title")
current_video = create(:poll_option_video, option: current_option, title: "Sample title")
patch :update, params: {
poll_question_answer_video: {
poll_question_option_video: {
title: "New title"
},
id: current_video,
answer_id: current_answer
option_id: current_option
}
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Video."
@@ -50,17 +50,17 @@ describe Admin::Poll::Questions::Answers::VideosController, :admin do
end
it "is possible for a not started poll" do
future_video = create(:poll_answer_video, answer: future_answer)
future_video = create(:poll_option_video, option: future_option)
patch :update, params: {
poll_question_answer_video: {
poll_question_option_video: {
title: "New title"
},
id: future_video,
answer_id: future_answer
option_id: future_option
}
expect(response).to redirect_to admin_answer_videos_path(future_answer)
expect(response).to redirect_to admin_option_videos_path(future_option)
expect(flash[:notice]).to eq "Changes saved"
expect(future_video.reload.title).to eq "New title"
end
@@ -68,20 +68,20 @@ describe Admin::Poll::Questions::Answers::VideosController, :admin do
describe "DELETE destroy" do
it "is not possible for an already started poll" do
current_video = create(:poll_answer_video, answer: current_answer)
delete :destroy, params: { answer_id: current_answer, id: current_video }
current_video = create(:poll_option_video, option: current_option)
delete :destroy, params: { option_id: current_option, id: current_video }
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'destroy' on Video."
expect(Poll::Question::Answer::Video.count).to eq 1
expect(Poll::Question::Option::Video.count).to eq 1
end
it "is possible for a not started poll" do
future_video = create(:poll_answer_video, answer: future_answer)
delete :destroy, params: { answer_id: future_answer, id: future_video }
future_video = create(:poll_option_video, option: future_option)
delete :destroy, params: { option_id: future_option, id: future_video }
expect(response).to redirect_to admin_answer_videos_path(future_answer)
expect(response).to redirect_to admin_option_videos_path(future_option)
expect(flash[:notice]).to eq "Answer video deleted successfully."
expect(Poll::Question::Answer::Video.count).to eq 0
expect(Poll::Question::Option::Video.count).to eq 0
end
end
end

View File

@@ -1,13 +1,13 @@
require "rails_helper"
describe Admin::Poll::Questions::AnswersController, :admin do
describe Admin::Poll::Questions::OptionsController, :admin do
let(:current_question) { create(:poll_question, poll: create(:poll)) }
let(:future_question) { create(:poll_question, poll: create(:poll, :future)) }
describe "POST create" do
it "is not possible for an already started poll" do
post :create, params: {
poll_question_answer: {
poll_question_option: {
translations_attributes: {
"0" => {
locale: "en",
@@ -18,13 +18,13 @@ describe Admin::Poll::Questions::AnswersController, :admin do
question_id: current_question
}
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'create' on Answer."
expect(Poll::Question::Answer.count).to eq 0
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'create' on Option."
expect(Poll::Question::Option.count).to eq 0
end
it "is possible for a not started poll" do
post :create, params: {
poll_question_answer: {
poll_question_option: {
translations_attributes: {
"0" => {
locale: "en",
@@ -36,72 +36,72 @@ describe Admin::Poll::Questions::AnswersController, :admin do
}
expect(response).to redirect_to admin_question_path(future_question)
expect(Poll::Question::Answer.last.title).to eq "Answer from future poll"
expect(Poll::Question::Answer.count).to eq 1
expect(Poll::Question::Option.last.title).to eq "Answer from future poll"
expect(Poll::Question::Option.count).to eq 1
end
end
describe "PATCH update" do
it "is not possible for an already started poll" do
current_answer = create(:poll_question_answer, question: current_question, title: "Sample title")
current_option = create(:poll_question_option, question: current_question, title: "Sample title")
patch :update, params: {
poll_question_answer: {
poll_question_option: {
translations_attributes: {
"0" => {
locale: "en",
title: "New title",
id: current_answer.translations.first.id
id: current_option.translations.first.id
}
}
},
question_id: current_question,
id: current_answer
id: current_option
}
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Answer."
expect(current_answer.reload.title).to eq "Sample title"
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'update' on Option."
expect(current_option.reload.title).to eq "Sample title"
end
it "is possible for a not started poll" do
future_answer = create(:poll_question_answer, question: future_question)
future_option = create(:poll_question_option, question: future_question)
patch :update, params: {
poll_question_answer: {
poll_question_option: {
translations_attributes: {
"0" => {
locale: "en",
title: "New title",
id: future_answer.translations.first.id
id: future_option.translations.first.id
}
}
},
question_id: future_question,
id: future_answer
id: future_option
}
expect(response).to redirect_to admin_question_path(future_question)
expect(flash[:notice]).to eq "Changes saved"
expect(future_answer.reload.title).to eq "New title"
expect(future_option.reload.title).to eq "New title"
end
end
describe "DELETE destroy" do
it "is not possible for an already started poll" do
current_answer = create(:poll_question_answer, question: current_question)
delete :destroy, params: { question_id: current_question, id: current_answer }
current_option = create(:poll_question_option, question: current_question)
delete :destroy, params: { question_id: current_question, id: current_option }
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'destroy' on Answer."
expect(Poll::Question::Answer.count).to eq 1
expect(flash[:alert]).to eq "You do not have permission to carry out the action 'destroy' on Option."
expect(Poll::Question::Option.count).to eq 1
end
it "is possible for a not started poll" do
future_answer = create(:poll_question_answer, question: future_question)
delete :destroy, params: { question_id: future_question, id: future_answer }
future_option = create(:poll_question_option, question: future_question)
delete :destroy, params: { question_id: future_question, id: future_option }
expect(response).to redirect_to admin_question_path(future_question)
expect(flash[:notice]).to eq "Answer deleted successfully"
expect(Poll::Question::Answer.count).to eq 0
expect(Poll::Question::Option.count).to eq 0
end
end
end

View File

@@ -3,8 +3,8 @@ require "rails_helper"
describe DocumentsController do
describe "DELETE destroy" do
context "Poll answers administration", :admin do
let(:current_answer) { create(:poll_question_answer, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_answer, poll: create(:poll, :future)) }
let(:current_answer) { create(:poll_question_option, poll: create(:poll)) }
let(:future_answer) { create(:poll_question_option, poll: create(:poll, :future)) }
it "is not possible for an already started poll" do
document = create(:document, documentable: current_answer)
@@ -17,10 +17,10 @@ describe DocumentsController do
it "is possible for a not started poll" do
document = create(:document, documentable: future_answer)
request.env["HTTP_REFERER"] = admin_answer_documents_path(future_answer)
request.env["HTTP_REFERER"] = admin_option_documents_path(future_answer)
delete :destroy, params: { id: document }
expect(response).to redirect_to admin_answer_documents_path(future_answer)
expect(response).to redirect_to admin_option_documents_path(future_answer)
expect(flash[:notice]).to eq "Document was deleted successfully."
expect(Document.count).to eq 0
end

View File

@@ -60,15 +60,15 @@ FactoryBot.define do
trait :yes_no do
after(:create) do |question|
create(:poll_question_answer, question: question, title: "Yes")
create(:poll_question_answer, question: question, title: "No")
create(:poll_question_option, question: question, title: "Yes")
create(:poll_question_option, question: question, title: "No")
end
end
trait :abc do
after(:create) do |question, evaluator|
%w[A B C].each do |letter|
create(:poll_question_answer, question: question, title: "Answer #{letter}")
create(:poll_question_option, question: question, title: "Answer #{letter}")
end
end
end
@@ -88,7 +88,7 @@ FactoryBot.define do
end
end
factory :poll_question_answer, class: "Poll::Question::Answer" do
factory :poll_question_option, class: "Poll::Question::Option" do
sequence(:title) { |n| "Answer title #{n}" }
sequence(:description) { |n| "Answer description #{n}" }
sequence(:given_order) { |n| n }
@@ -98,29 +98,29 @@ FactoryBot.define do
question { association(:poll_question, poll: poll) }
trait :with_image do
after(:create) { |answer| create(:image, imageable: answer) }
after(:create) { |option| create(:image, imageable: option) }
end
trait :with_document do
after(:create) { |answer| create(:document, documentable: answer) }
after(:create) { |option| create(:document, documentable: option) }
end
trait :with_video do
after(:create) { |answer| create(:poll_answer_video, answer: answer) }
after(:create) { |option| create(:poll_option_video, option: option) }
end
factory :future_poll_question_answer do
factory :future_poll_question_option do
poll { association(:poll, :future) }
end
end
factory :poll_answer_video, class: "Poll::Question::Answer::Video" do
factory :poll_option_video, class: "Poll::Question::Option::Video" do
title { "Sample video title" }
url { "https://youtu.be/nhuNb0XtRhQ" }
transient { poll { association(:poll) } }
answer { association(:poll_question_answer, poll: poll) }
option { association(:poll_question_option, poll: poll) }
end
factory :poll_booth, class: "Poll::Booth" do
@@ -204,14 +204,14 @@ FactoryBot.define do
factory :poll_answer, class: "Poll::Answer" do
question factory: [:poll_question, :yes_no]
author factory: [:user, :level_two]
answer { question.question_answers.sample.title }
answer { question.question_options.sample.title }
end
factory :poll_partial_result, class: "Poll::PartialResult" do
question factory: [:poll_question, :yes_no]
author factory: :user
origin { "web" }
answer { question.question_answers.sample.title }
answer { question.question_options.sample.title }
end
factory :poll_recount, class: "Poll::Recount" do

View File

@@ -20,14 +20,14 @@ describe Abilities::Administrator do
let(:future_poll) { create(:poll, :future) }
let(:current_poll_question) { create(:poll_question) }
let(:future_poll_question) { create(:poll_question, poll: future_poll) }
let(:current_poll_question_answer) { create(:poll_question_answer) }
let(:future_poll_question_answer) { create(:poll_question_answer, poll: future_poll) }
let(:current_poll_answer_video) { create(:poll_answer_video, answer: current_poll_question_answer) }
let(:future_poll_answer_video) { create(:poll_answer_video, answer: future_poll_question_answer) }
let(:current_poll_answer_image) { build(:image, imageable: current_poll_question_answer) }
let(:future_poll_answer_image) { build(:image, imageable: future_poll_question_answer) }
let(:current_poll_answer_document) { build(:document, documentable: current_poll_question_answer) }
let(:future_poll_answer_document) { build(:document, documentable: future_poll_question_answer) }
let(:current_poll_question_option) { create(:poll_question_option) }
let(:future_poll_question_option) { create(:poll_question_option, poll: future_poll) }
let(:current_poll_option_video) { create(:poll_option_video, option: current_poll_question_option) }
let(:future_poll_option_video) { create(:poll_option_video, option: future_poll_question_option) }
let(:current_poll_option_image) { build(:image, imageable: current_poll_question_option) }
let(:future_poll_option_image) { build(:image, imageable: future_poll_question_option) }
let(:current_poll_option_document) { build(:document, documentable: current_poll_question_option) }
let(:future_poll_option_document) { build(:document, documentable: future_poll_question_option) }
let(:past_process) { create(:legislation_process, :past) }
let(:past_draft_process) { create(:legislation_process, :past, :not_published) }
@@ -131,27 +131,27 @@ describe Abilities::Administrator do
it { should_not be_able_to(:update, current_poll_question) }
it { should_not be_able_to(:destroy, current_poll_question) }
it { should be_able_to(:read, Poll::Question::Answer) }
it { should be_able_to(:order_answers, Poll::Question::Answer) }
it { should be_able_to(:create, future_poll_question_answer) }
it { should be_able_to(:update, future_poll_question_answer) }
it { should be_able_to(:destroy, future_poll_question_answer) }
it { should_not be_able_to(:create, current_poll_question_answer) }
it { should_not be_able_to(:update, current_poll_question_answer) }
it { should_not be_able_to(:destroy, current_poll_question_answer) }
it { should be_able_to(:read, Poll::Question::Option) }
it { should be_able_to(:order_options, Poll::Question::Option) }
it { should be_able_to(:create, future_poll_question_option) }
it { should be_able_to(:update, future_poll_question_option) }
it { should be_able_to(:destroy, future_poll_question_option) }
it { should_not be_able_to(:create, current_poll_question_option) }
it { should_not be_able_to(:update, current_poll_question_option) }
it { should_not be_able_to(:destroy, current_poll_question_option) }
it { should be_able_to(:create, future_poll_answer_video) }
it { should be_able_to(:update, future_poll_answer_video) }
it { should be_able_to(:destroy, future_poll_answer_video) }
it { should_not be_able_to(:create, current_poll_answer_video) }
it { should_not be_able_to(:update, current_poll_answer_video) }
it { should_not be_able_to(:destroy, current_poll_answer_video) }
it { should be_able_to(:create, future_poll_option_video) }
it { should be_able_to(:update, future_poll_option_video) }
it { should be_able_to(:destroy, future_poll_option_video) }
it { should_not be_able_to(:create, current_poll_option_video) }
it { should_not be_able_to(:update, current_poll_option_video) }
it { should_not be_able_to(:destroy, current_poll_option_video) }
it { should be_able_to(:destroy, future_poll_answer_image) }
it { should_not be_able_to(:destroy, current_poll_answer_image) }
it { should be_able_to(:destroy, future_poll_option_image) }
it { should_not be_able_to(:destroy, current_poll_option_image) }
it { should be_able_to(:destroy, future_poll_answer_document) }
it { should_not be_able_to(:destroy, current_poll_answer_document) }
it { should be_able_to(:destroy, future_poll_option_document) }
it { should_not be_able_to(:destroy, current_poll_option_document) }
it { is_expected.to be_able_to :manage, Dashboard::AdministratorTask }
it { is_expected.to be_able_to :manage, dashboard_administrator_task }

View File

@@ -47,11 +47,11 @@ describe Poll::Answer do
expect(Poll::Answer.count).to be 2
end
it "is valid for answers included in the Poll::Question's question_answers list" do
it "is valid for answers included in the Poll::Question's question_options list" do
question = create(:poll_question)
create(:poll_question_answer, title: "One", question: question)
create(:poll_question_answer, title: "Two", question: question)
create(:poll_question_answer, title: "Three", question: question)
create(:poll_question_option, title: "One", question: question)
create(:poll_question_option, title: "Two", question: question)
create(:poll_question_option, title: "Three", question: question)
expect(build(:poll_answer, question: question, answer: "One")).to be_valid
expect(build(:poll_answer, question: question, answer: "Two")).to be_valid

View File

@@ -4,9 +4,9 @@ describe Poll::PartialResult do
describe "validations" do
it "validates that the answers are included in the Poll::Question's list" do
question = create(:poll_question)
create(:poll_question_answer, title: "One", question: question)
create(:poll_question_answer, title: "Two", question: question)
create(:poll_question_answer, title: "Three", question: question)
create(:poll_question_option, title: "One", question: question)
create(:poll_question_option, title: "Two", question: question)
create(:poll_question_option, title: "Three", question: question)
expect(build(:poll_partial_result, question: question, answer: "One")).to be_valid
expect(build(:poll_partial_result, question: question, answer: "Two")).to be_valid

View File

@@ -1,63 +0,0 @@
require "rails_helper"
describe Poll::Question::Answer do
it_behaves_like "globalizable", :poll_question_answer
describe "#with_content" do
it "returns answers with a description" do
answer = create(:poll_question_answer, description: "I've got a description")
expect(Poll::Question::Answer.with_content).to eq [answer]
end
it "returns answers with images and no description" do
answer = create(:poll_question_answer, :with_image, description: "")
expect(Poll::Question::Answer.with_content).to eq [answer]
end
it "returns answers with documents and no description" do
answer = create(:poll_question_answer, :with_document, description: "")
expect(Poll::Question::Answer.with_content).to eq [answer]
end
it "returns answers with videos and no description" do
answer = create(:poll_question_answer, :with_video, description: "")
expect(Poll::Question::Answer.with_content).to eq [answer]
end
it "does not return answers with no description and no images, documents nor videos" do
create(:poll_question_answer, description: "")
expect(Poll::Question::Answer.with_content).to be_empty
end
end
describe "#with_read_more?" do
it "returns false when the answer does not have description, images, videos nor documents" do
answer = build(:poll_question_answer, description: nil)
expect(answer.with_read_more?).to be_falsy
end
it "returns true when the answer has description, images, videos or documents" do
answer = build(:poll_question_answer, description: "Answer description")
expect(answer.with_read_more?).to be_truthy
answer = build(:poll_question_answer, :with_image)
expect(answer.with_read_more?).to be_truthy
answer = build(:poll_question_answer, :with_document)
expect(answer.with_read_more?).to be_truthy
answer = build(:poll_question_answer, :with_video)
expect(answer.with_read_more?).to be_truthy
end
end
end

View File

@@ -0,0 +1,63 @@
require "rails_helper"
describe Poll::Question::Option do
it_behaves_like "globalizable", :poll_question_option
describe "#with_content" do
it "returns options with a description" do
option = create(:poll_question_option, description: "I've got a description")
expect(Poll::Question::Option.with_content).to eq [option]
end
it "returns options with images and no description" do
option = create(:poll_question_option, :with_image, description: "")
expect(Poll::Question::Option.with_content).to eq [option]
end
it "returns options with documents and no description" do
option = create(:poll_question_option, :with_document, description: "")
expect(Poll::Question::Option.with_content).to eq [option]
end
it "returns options with videos and no description" do
option = create(:poll_question_option, :with_video, description: "")
expect(Poll::Question::Option.with_content).to eq [option]
end
it "does not return options with no description and no images, documents nor videos" do
create(:poll_question_option, description: "")
expect(Poll::Question::Option.with_content).to be_empty
end
end
describe "#with_read_more?" do
it "returns false when the option does not have description, images, videos nor documents" do
option = build(:poll_question_option, description: nil)
expect(option.with_read_more?).to be_falsy
end
it "returns true when the option has description, images, videos or documents" do
option = build(:poll_question_option, description: "Option description")
expect(option.with_read_more?).to be_truthy
option = build(:poll_question_option, :with_image)
expect(option.with_read_more?).to be_truthy
option = build(:poll_question_option, :with_document)
expect(option.with_read_more?).to be_truthy
option = build(:poll_question_option, :with_video)
expect(option.with_read_more?).to be_truthy
end
end
end

View File

@@ -115,9 +115,9 @@ describe "Polymorphic routes" do
end
it "routes poll answer videos" do
video = create(:poll_answer_video)
video = create(:poll_option_video)
expect(admin_polymorphic_path(video)).to eq admin_answer_video_path(video.answer, video)
expect(admin_polymorphic_path(video)).to eq admin_option_video_path(video.option, video)
end
it "routes milestones for resources with no hierarchy" do

View File

@@ -125,7 +125,7 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
end
scenario "Render image preview after sending the form with validation errors",
unless: imageable_factory_name == "poll_question_answer" do
unless: imageable_factory_name == "poll_question_option" do
do_login_for user, management: management
visit send(path, arguments)

View File

@@ -236,8 +236,8 @@ describe "Admin booths assignments", :admin do
question_1 = create(:poll_question, :yes_no, poll: poll)
question_2 = create(:poll_question, poll: poll)
create(:poll_question_answer, title: "Today", question: question_2)
create(:poll_question_answer, title: "Tomorrow", question: question_2)
create(:poll_question_option, title: "Today", question: question_2)
create(:poll_question_option, title: "Tomorrow", question: question_2)
create(:poll_partial_result,
booth_assignment: booth_assignment,

View File

@@ -133,12 +133,12 @@ describe "Admin polls", :admin do
expect(page).not_to have_content("Do you support CONSUL?")
expect(Poll::Question.count).to eq(0)
expect(Poll::Question::Answer.count).to eq(0)
expect(Poll::Question::Option.count).to eq(0)
end
scenario "Can destroy polls with answers including videos" do
scenario "Can destroy polls with options including videos" do
poll = create(:poll, name: "Do you support CONSUL?")
create(:poll_answer_video, poll: poll)
create(:poll_option_video, poll: poll)
visit admin_polls_path
@@ -354,12 +354,12 @@ describe "Admin polls", :admin do
booth_assignment_3 = create(:poll_booth_assignment, poll: poll)
question_1 = create(:poll_question, poll: poll)
create(:poll_question_answer, title: "Oui", question: question_1)
create(:poll_question_answer, title: "Non", question: question_1)
create(:poll_question_option, title: "Oui", question: question_1)
create(:poll_question_option, title: "Non", question: question_1)
question_2 = create(:poll_question, poll: poll)
create(:poll_question_answer, title: "Aujourd'hui", question: question_2)
create(:poll_question_answer, title: "Demain", question: question_2)
create(:poll_question_option, title: "Aujourd'hui", question: question_2)
create(:poll_question_option, title: "Demain", question: question_2)
[booth_assignment_1, booth_assignment_2, booth_assignment_3].each do |ba|
create(:poll_partial_result,
@@ -430,8 +430,8 @@ describe "Admin polls", :admin do
question_1 = create(:poll_question, :yes_no, poll: poll)
question_2 = create(:poll_question, poll: poll)
create(:poll_question_answer, title: "Today", question: question_2)
create(:poll_question_answer, title: "Tomorrow", question: question_2)
create(:poll_question_option, title: "Today", question: question_2)
create(:poll_question_option, title: "Tomorrow", question: question_2)
[booth_assignment_1, booth_assignment_2, booth_assignment_3].each do |ba|
create(:poll_partial_result,
@@ -456,17 +456,17 @@ describe "Admin polls", :admin do
click_link "Results"
expect(page).to have_content(question_1.title)
question_1.question_answers.each_with_index do |answer, i|
question_1.question_options.each_with_index do |option, i|
within("#question_#{question_1.id}_#{i}_result") do
expect(page).to have_content(answer.title)
expect(page).to have_content(option.title)
expect(page).to have_content([33, 0][i])
end
end
expect(page).to have_content(question_2.title)
question_2.question_answers.each_with_index do |answer, i|
question_2.question_options.each_with_index do |option, i|
within("#question_#{question_2.id}_#{i}_result") do
expect(page).to have_content(answer.title)
expect(page).to have_content(option.title)
expect(page).to have_content([0, 15][i])
end
end

View File

@@ -4,31 +4,31 @@ describe "Documents", :admin do
let(:future_poll) { create(:poll, :future) }
context "Index" do
scenario "Answer with no documents" do
answer = create(:poll_question_answer)
scenario "Option with no documents" do
option = create(:poll_question_option)
document = create(:document)
visit admin_answer_documents_path(answer)
visit admin_option_documents_path(option)
expect(page).not_to have_content(document.title)
expect(page).to have_link "Go back", href: admin_question_path(answer.question)
expect(page).to have_link "Go back", href: admin_question_path(option.question)
end
scenario "Answer with documents" do
answer = create(:poll_question_answer)
document = create(:document, documentable: answer)
scenario "Option with documents" do
option = create(:poll_question_option)
document = create(:document, documentable: option)
visit admin_answer_documents_path(answer)
visit admin_option_documents_path(option)
expect(page).to have_content(document.title)
end
end
describe "Create document for answer" do
describe "Create document for option" do
scenario "with valid data" do
answer = create(:poll_question_answer, poll: future_poll)
option = create(:poll_question_option, poll: future_poll)
visit admin_answer_documents_path(answer)
visit admin_option_documents_path(option)
expect(page).not_to have_link "Download file"
@@ -43,9 +43,9 @@ describe "Documents", :admin do
end
scenario "with invalid data" do
answer = create(:poll_question_answer, poll: future_poll)
option = create(:poll_question_option, poll: future_poll)
visit admin_answer_documents_path(answer)
visit admin_option_documents_path(option)
documentable_attach_new_file(Rails.root.join("spec/fixtures/files/clippy.pdf"))
fill_in "Title", with: ""
@@ -56,11 +56,11 @@ describe "Documents", :admin do
end
end
scenario "Remove document from answer" do
answer = create(:poll_question_answer, poll: future_poll)
document = create(:document, documentable: answer)
scenario "Remove document from option" do
option = create(:poll_question_option, poll: future_poll)
document = create(:document, documentable: option)
visit admin_answer_documents_path(answer)
visit admin_option_documents_path(option)
expect(page).to have_content(document.title)
accept_confirm("Are you sure? This action will delete \"#{document.title}\" and can't be undone.") do

View File

@@ -5,39 +5,39 @@ describe "Images", :admin do
let(:current_poll) { create(:poll) }
it_behaves_like "nested imageable",
"future_poll_question_answer",
"new_admin_answer_image_path",
{ answer_id: "id" },
"future_poll_question_option",
"new_admin_option_image_path",
{ option_id: "id" },
nil,
"Save image",
"Image uploaded successfully",
true
context "Index" do
scenario "Answer with no images" do
answer = create(:poll_question_answer)
scenario "Option with no images" do
option = create(:poll_question_option)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).not_to have_css("img[title='']")
end
scenario "Answer with images" do
answer = create(:poll_question_answer)
image = create(:image, imageable: answer)
scenario "Option with images" do
option = create(:poll_question_option)
image = create(:image, imageable: option)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).to have_css("img[title='#{image.title}']")
expect(page).to have_content(image.title)
end
end
describe "Add image to answer" do
describe "Add image to option" do
scenario "Is possible for a not started poll" do
answer = create(:poll_question_answer, poll: future_poll)
option = create(:poll_question_option, poll: future_poll)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).not_to have_css "img[title='clippy.jpg']"
expect(page).not_to have_content "clippy.jpg"
@@ -54,21 +54,21 @@ describe "Images", :admin do
end
scenario "Is not possible for an already started poll" do
answer = create(:poll_question_answer, poll: current_poll)
option = create(:poll_question_option, poll: current_poll)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).not_to have_link "Add image"
expect(page).to have_content "Once the poll has started it will not be possible to create, edit or"
end
end
describe "Remove image from answer" do
describe "Remove image from option" do
scenario "Is possible for a not started poll" do
answer = create(:poll_question_answer, poll: future_poll)
image = create(:image, imageable: answer)
option = create(:poll_question_option, poll: future_poll)
image = create(:image, imageable: option)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).to have_css "img[title='#{image.title}']"
expect(page).to have_content image.title
@@ -81,10 +81,10 @@ describe "Images", :admin do
end
scenario "Is not possible for an already started poll" do
answer = create(:poll_question_answer, poll: current_poll)
image = create(:image, imageable: answer)
option = create(:poll_question_option, poll: current_poll)
image = create(:image, imageable: option)
visit admin_answer_images_path(answer)
visit admin_option_images_path(option)
expect(page).to have_css "img[title='#{image.title}']"
expect(page).to have_content image.title

View File

@@ -1,6 +1,6 @@
require "rails_helper"
describe "Answers", :admin do
describe "Poll question options", :admin do
let(:future_poll) { create(:poll, :future) }
let(:current_poll) { create(:poll) }
@@ -34,7 +34,7 @@ describe "Answers", :admin do
scenario "Create second answer and place after the first one" do
question = create(:poll_question, poll: future_poll)
create(:poll_question_answer, title: "First", question: question, given_order: 1)
create(:poll_question_option, title: "First", question: question, given_order: 1)
visit admin_question_path(question)
click_link "Add answer"
@@ -50,8 +50,8 @@ describe "Answers", :admin do
scenario "Update" do
question = create(:poll_question, poll: future_poll)
create(:poll_question_answer, question: question, title: "Answer title", given_order: 2)
create(:poll_question_answer, question: question, title: "Another title", given_order: 1)
create(:poll_question_option, question: question, title: "Answer title", given_order: 2)
create(:poll_question_option, question: question, title: "Another title", given_order: 1)
visit admin_question_path(question)
within("tr", text: "Answer title") { click_link "Edit" }
@@ -72,9 +72,9 @@ describe "Answers", :admin do
end
scenario "Destroy" do
answer = create(:poll_question_answer, poll: future_poll, title: "I'm not useful")
option = create(:poll_question_option, poll: future_poll, title: "I'm not useful")
visit admin_question_path(answer.question)
visit admin_question_path(option.question)
within("tr", text: "I'm not useful") do
accept_confirm("Are you sure? This action will delete \"I'm not useful\" and can't be undone.") do
@@ -88,8 +88,8 @@ describe "Answers", :admin do
scenario "Reorder" do
question = create(:poll_question)
create(:poll_question_answer, question: question, title: "First", given_order: 1)
create(:poll_question_answer, question: question, title: "Last", given_order: 2)
create(:poll_question_option, question: question, title: "First", given_order: 1)
create(:poll_question_option, question: question, title: "Last", given_order: 2)
visit admin_question_path(question)

View File

@@ -9,11 +9,11 @@ describe "Videos", :admin do
describe "Create" do
scenario "Is possible for a not started poll" do
question = create(:poll_question, poll: future_poll)
answer = create(:poll_question_answer, question: question)
option = create(:poll_question_option, question: question)
visit admin_question_path(question)
within("#poll_question_answer_#{answer.id}") do
within("#poll_question_option_#{option.id}") do
click_link "Video list"
end
click_link "Add video"
@@ -29,9 +29,9 @@ describe "Videos", :admin do
end
scenario "Is not possible for an already started poll" do
answer = create(:poll_question_answer, poll: current_poll)
option = create(:poll_question_option, poll: current_poll)
visit admin_answer_videos_path(answer)
visit admin_option_videos_path(option)
expect(page).not_to have_link "Add video"
expect(page).to have_content "Once the poll has started it will not be possible to create, edit or"
@@ -39,11 +39,11 @@ describe "Videos", :admin do
end
scenario "Update" do
video = create(:poll_answer_video, poll: future_poll)
video = create(:poll_option_video, poll: future_poll)
visit edit_admin_answer_video_path(video.answer, video)
visit edit_admin_option_video_path(video.option, video)
expect(page).to have_link "Go back", href: admin_answer_videos_path(video.answer)
expect(page).to have_link "Go back", href: admin_option_videos_path(video.option)
fill_in "Title", with: title
fill_in "External video", with: url
@@ -56,9 +56,9 @@ describe "Videos", :admin do
end
scenario "Destroy" do
video = create(:poll_answer_video, poll: future_poll)
video = create(:poll_option_video, poll: future_poll)
visit admin_answer_videos_path(video.answer)
visit admin_option_videos_path(video.option)
within("tr", text: video.title) do
accept_confirm("Are you sure? This action will delete \"#{video.title}\" and can't be undone.") do

View File

@@ -215,8 +215,8 @@ describe "Admin edit translatable records", :admin do
end
context "CKEditor fields" do
let(:translatable) { create(:poll_question_answer, poll: create(:poll, :future)) }
let(:path) { edit_admin_question_answer_path(translatable.question, translatable) }
let(:translatable) { create(:poll_question_option, poll: create(:poll, :future)) }
let(:path) { edit_admin_question_option_path(translatable.question, translatable) }
scenario "Changes the existing translation" do
visit path

View File

@@ -9,11 +9,11 @@ describe "Officing Results", :with_frozen_time do
before do
create(:poll_shift, :recount_scrutiny_task, officer: poll_officer, booth: booth, date: Date.current)
create(:poll_question_answer, title: "Yes", question: question_1, given_order: 1)
create(:poll_question_answer, title: "No", question: question_1, given_order: 2)
create(:poll_question_option, title: "Yes", question: question_1, given_order: 1)
create(:poll_question_option, title: "No", question: question_1, given_order: 2)
create(:poll_question_answer, title: "Today", question: question_2, given_order: 1)
create(:poll_question_answer, title: "Tomorrow", question: question_2, given_order: 2)
create(:poll_question_option, title: "Today", question: question_2, given_order: 1)
create(:poll_question_option, title: "Tomorrow", question: question_2, given_order: 2)
login_as(poll_officer.user)
set_officing_booth(booth)
@@ -86,7 +86,7 @@ describe "Officing Results", :with_frozen_time do
booth_assignment: poll_officer.officer_assignments.first.booth_assignment,
date: Date.current,
question: question_1,
answer: question_1.question_answers.first.title,
answer: question_1.question_options.first.title,
author: poll_officer.user,
amount: 7777
)
@@ -160,12 +160,12 @@ describe "Officing Results", :with_frozen_time do
expect(page).to have_content(booth.name)
expect(page).to have_content(question_1.title)
question_1.question_answers.each_with_index do |answer, i|
question_1.question_options.each_with_index do |answer, i|
within("#question_#{question_1.id}_#{i}_result") { expect(page).to have_content(answer.title) }
end
expect(page).to have_content(question_2.title)
question_2.question_answers.each_with_index do |answer, i|
question_2.question_options.each_with_index do |answer, i|
within("#question_#{question_2.id}_#{i}_result") { expect(page).to have_content(answer.title) }
end

View File

@@ -152,8 +152,8 @@ describe "Polls" do
scenario "Buttons to slide through images work back and forth" do
question = create(:poll_question, :yes_no, poll: poll)
create(:image, imageable: question.question_answers.last, title: "The no movement")
create(:image, imageable: question.question_answers.last, title: "No movement planning")
create(:image, imageable: question.question_options.last, title: "The no movement")
create(:image, imageable: question.question_options.last, title: "No movement planning")
visit poll_path(poll)

View File

@@ -13,8 +13,8 @@ describe "Poll Questions" do
scenario "shows answers with an image and no description" do
poll = create(:poll)
answer = create(:poll_question_answer, poll: poll, title: "Pedestrian road", description: "")
create(:image, imageable: answer, title: "Trees on both sides of the road")
option = create(:poll_question_option, poll: poll, title: "Pedestrian road", description: "")
create(:image, imageable: option, title: "Trees on both sides of the road")
visit poll_path(poll)

View File

@@ -8,13 +8,13 @@ describe "Poll Results" do
poll = create(:poll, results_enabled: true)
question1 = create(:poll_question, poll: poll)
answer1 = create(:poll_question_answer, question: question1, title: "Yes")
answer2 = create(:poll_question_answer, question: question1, title: "No")
answer1 = create(:poll_question_option, question: question1, title: "Yes")
answer2 = create(:poll_question_option, question: question1, title: "No")
question2 = create(:poll_question, poll: poll)
answer3 = create(:poll_question_answer, question: question2, title: "Blue")
answer4 = create(:poll_question_answer, question: question2, title: "Green")
answer5 = create(:poll_question_answer, question: question2, title: "Yellow")
answer3 = create(:poll_question_option, question: question2, title: "Blue")
answer4 = create(:poll_question_option, question: question2, title: "Green")
answer5 = create(:poll_question_option, question: question2, title: "Yellow")
login_as user1
vote_for_poll_via_web(poll, question1, "Yes")