Allow undo votes in favor against component
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
title: t("votes.agree"),
|
||||
"aria-label": agree_aria_label,
|
||||
"aria-pressed": pressed?("yes"),
|
||||
method: "post",
|
||||
method: user_already_voted_with("yes") ? "delete" : "post",
|
||||
remote: true do %>
|
||||
<span class="show-for-sr"><%= t("votes.agree") %></span>
|
||||
<% end %>
|
||||
@@ -16,7 +16,7 @@
|
||||
title: t("votes.disagree"),
|
||||
"aria-label": disagree_aria_label,
|
||||
"aria-pressed": pressed?("no"),
|
||||
method: "post",
|
||||
method: user_already_voted_with("no") ? "delete" : "post",
|
||||
remote: true do %>
|
||||
<span class="show-for-sr"><%= t("votes.disagree") %></span>
|
||||
<% end %>
|
||||
|
||||
@@ -28,10 +28,31 @@ class Shared::InFavorAgainstComponent < ApplicationComponent
|
||||
end
|
||||
|
||||
def vote_in_favor_against_path(value)
|
||||
if votable.class.name == "Debate"
|
||||
debate_votes_path(votable, value: value)
|
||||
if user_already_voted_with(value)
|
||||
remove_vote_path(value)
|
||||
else
|
||||
legislation_process_proposal_votes_path(votable.process, votable, value: value)
|
||||
if votable.class.name == "Debate"
|
||||
debate_votes_path(votable, value: value)
|
||||
else
|
||||
legislation_process_proposal_votes_path(votable.process, votable, value: value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def user_already_voted_with(value)
|
||||
current_user&.voted_as_when_voted_for(votable) == parse_vote(value)
|
||||
end
|
||||
|
||||
def remove_vote_path(value)
|
||||
vote = votable.votes_for.find_by!(voter: current_user)
|
||||
if votable.class.name == "Debate"
|
||||
debate_vote_path(votable, vote, value: value)
|
||||
else
|
||||
legislation_process_proposal_vote_path(votable.process, votable, vote, value: value)
|
||||
end
|
||||
end
|
||||
|
||||
def parse_vote(value)
|
||||
value == "yes" ? true : false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ module Debates
|
||||
class VotesController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
load_and_authorize_resource :debate
|
||||
load_and_authorize_resource through: :debate, through_association: :votes_for, only: :destroy
|
||||
|
||||
def create
|
||||
authorize! :create, Vote.new(voter: current_user, votable: @debate)
|
||||
@@ -11,5 +12,13 @@ module Debates
|
||||
format.js { render :show }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@debate.unvote_by(current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render :show }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ module Legislation
|
||||
before_action :authenticate_user!
|
||||
load_and_authorize_resource :process, class: "Legislation::Process"
|
||||
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
|
||||
load_and_authorize_resource through: :proposal, through_association: :votes_for, only: :destroy
|
||||
|
||||
def create
|
||||
authorize! :create, Vote.new(voter: current_user, votable: @proposal)
|
||||
@@ -13,6 +14,14 @@ module Legislation
|
||||
format.js { render :show }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@proposal.unvote_by(current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render :show }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -81,14 +81,14 @@ module Abilities
|
||||
can [:create, :destroy], DirectUpload
|
||||
|
||||
unless user.organization?
|
||||
can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
|
||||
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
|
||||
can :vote, Comment
|
||||
end
|
||||
|
||||
if user.level_two_or_three_verified?
|
||||
can :vote, Proposal, &:published?
|
||||
|
||||
can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Legislation::Proposal"
|
||||
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Legislation::Proposal"
|
||||
|
||||
can :create, Legislation::Answer
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@ resources :debates do
|
||||
put "recommendations/disable", only: :index, controller: "debates", action: :disable_recommendations
|
||||
end
|
||||
|
||||
resources :votes, controller: "debates/votes", only: :create
|
||||
resources :votes, controller: "debates/votes", only: [:create, :destroy]
|
||||
end
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace :legislation do
|
||||
get :suggest
|
||||
end
|
||||
|
||||
resources :votes, controller: "proposals/votes", only: :create
|
||||
resources :votes, controller: "proposals/votes", only: [:create, :destroy]
|
||||
end
|
||||
|
||||
resources :draft_versions, only: [:show] do
|
||||
|
||||
@@ -22,6 +22,24 @@ describe Shared::InFavorAgainstComponent do
|
||||
end
|
||||
end
|
||||
|
||||
it "can undo vote when the user has already voted" do
|
||||
create(:vote, votable: debate, voter: user)
|
||||
|
||||
sign_in user
|
||||
|
||||
render_inline component
|
||||
|
||||
page.find(".in-favor") do |in_favor_block|
|
||||
expect(in_favor_block).to have_css "form[action*='votes'][method='post']"
|
||||
expect(in_favor_block).to have_css "input[name='_method'][value='delete']", visible: :hidden
|
||||
end
|
||||
|
||||
page.find(".against") do |against_block|
|
||||
expect(against_block).to have_css "form[action*='votes'][method='post']"
|
||||
expect(against_block).not_to have_css "input[name='_method']", visible: :all
|
||||
end
|
||||
end
|
||||
|
||||
it "does not include result percentages" do
|
||||
create(:vote, votable: debate)
|
||||
sign_in(user)
|
||||
|
||||
@@ -40,4 +40,17 @@ describe Debates::VotesController do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE destroy" do
|
||||
let(:user) { create(:user) }
|
||||
let(:debate) { create(:debate) }
|
||||
let!(:vote) { create(:vote, votable: debate, voter: user) }
|
||||
before { sign_in user }
|
||||
|
||||
it "allows undoing a vote if user is allowed" do
|
||||
expect do
|
||||
delete :destroy, xhr: true, params: { debate_id: debate.id, id: vote }
|
||||
end.to change { debate.reload.votes_for.size }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,4 +37,20 @@ describe Legislation::Proposals::VotesController do
|
||||
end.not_to change { proposal.reload.votes_for.size }
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE destroy" do
|
||||
let(:user) { create(:user, :level_two) }
|
||||
let!(:vote) { create(:vote, votable: proposal, voter: user) }
|
||||
let(:vote_params) do
|
||||
{ process_id: legislation_process.id, legislation_proposal_id: proposal.id, id: vote }
|
||||
end
|
||||
|
||||
it "allows undoing a vote" do
|
||||
sign_in user
|
||||
|
||||
expect do
|
||||
delete :destroy, xhr: true, params: vote_params
|
||||
end.to change { proposal.reload.votes_for.size }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -77,6 +77,8 @@ describe Abilities::Common do
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should be_able_to(:create, user.votes.build(votable: debate)) }
|
||||
it { should_not be_able_to(:create, another_user.votes.build(votable: debate)) }
|
||||
it { should be_able_to(:destroy, user.votes.build(votable: debate)) }
|
||||
it { should_not be_able_to(:destroy, another_user.votes.build(votable: debate)) }
|
||||
|
||||
it { should be_able_to(:show, user) }
|
||||
it { should be_able_to(:edit, user) }
|
||||
@@ -184,12 +186,15 @@ describe Abilities::Common do
|
||||
describe "vote legislation proposal" do
|
||||
context "when user is not level_two_or_three_verified" do
|
||||
it { should_not be_able_to(:create, user.votes.build(votable: legislation_proposal)) }
|
||||
it { should_not be_able_to(:destroy, user.votes.build(votable: legislation_proposal)) }
|
||||
end
|
||||
|
||||
context "when user is level_two_or_three_verified" do
|
||||
before { user.update(level_two_verified_at: Date.current) }
|
||||
it { should be_able_to(:create, user.votes.build(votable: legislation_proposal)) }
|
||||
it { should_not be_able_to(:create, another_user.votes.build(votable: legislation_proposal)) }
|
||||
it { should be_able_to(:destroy, user.votes.build(votable: legislation_proposal)) }
|
||||
it { should_not be_able_to(:destroy, another_user.votes.build(votable: legislation_proposal)) }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ describe "Abilities::Organization" do
|
||||
it { should be_able_to(:index, Debate) }
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should_not be_able_to(:create, user.votes.build(votable: debate)) }
|
||||
it { should_not be_able_to(:destroy, user.votes.build(votable: debate)) }
|
||||
|
||||
it { should be_able_to(:index, Proposal) }
|
||||
it { should be_able_to(:show, proposal) }
|
||||
|
||||
@@ -100,20 +100,27 @@ describe "Votes" do
|
||||
expect(page).to have_content "1 vote"
|
||||
end
|
||||
|
||||
scenario "Trying to vote multiple times" do
|
||||
scenario "Allow undoing votes" do
|
||||
visit debate_path(create(:debate))
|
||||
|
||||
click_button "I agree"
|
||||
|
||||
expect(page).to have_content "1 vote"
|
||||
expect(page).not_to have_content "No votes"
|
||||
|
||||
click_button "I agree"
|
||||
|
||||
expect(page).to have_content "No votes"
|
||||
expect(page).not_to have_content "2 votes"
|
||||
|
||||
within(".in-favor") do
|
||||
expect(page).to have_content "100%"
|
||||
expect(page).to have_content "0%"
|
||||
expect(page).to have_css "button[aria-pressed='false']"
|
||||
end
|
||||
|
||||
within(".against") do
|
||||
expect(page).to have_content "0%"
|
||||
expect(page).to have_css "button[aria-pressed='false']"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -337,4 +344,31 @@ describe "Votes" do
|
||||
expect(page).not_to have_button "Support", disabled: :all
|
||||
end
|
||||
end
|
||||
|
||||
describe "Legislation Proposals" do
|
||||
let(:proposal) { create(:legislation_proposal) }
|
||||
|
||||
scenario "Allow undoing votes" do
|
||||
login_as verified
|
||||
visit legislation_process_proposal_path(proposal.process, proposal)
|
||||
|
||||
click_button "I agree"
|
||||
|
||||
expect(page).to have_content "1 vote"
|
||||
expect(page).not_to have_content "No votes"
|
||||
|
||||
click_button "I agree"
|
||||
|
||||
expect(page).to have_content "No votes"
|
||||
expect(page).not_to have_content "2 votes"
|
||||
|
||||
within(".in-favor") do
|
||||
expect(page).to have_content "0%"
|
||||
end
|
||||
|
||||
within(".against") do
|
||||
expect(page).to have_content "0%"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user