Refactoring: Move 'vote' action to Comments::VotesControllers

As far as possible I think the code is clearer if we use CRUD actions
rather than custom actions. This will make it easier to add the action
to remove votes in the next commit.

Note that we are adding this line as we need to validate it that a vote
can be created on a comment by the current user:

```authorize! :create, Vote.new(voter: current_user, votable: @comment)```

We have done it this way and not with the following code as you might
expect, as this way two votes are created instead of one.

```load_and_authorize_resource through: :comment, through_association: :votes_for```

This line tries to load the resource @comment and through the association
"votes_for" it tries to create a new vote associated to that debate.
Therefore a vote is created when trying to authorise the resource and
then another one in the create action, when calling @comment.vote.
This commit is contained in:
taitus
2023-09-20 16:08:44 +02:00
parent b39b64a674
commit f87a332c3e
10 changed files with 58 additions and 15 deletions

View File

@@ -3,9 +3,9 @@
 |   | 
<span class="in-favor"> <span class="in-favor">
<%= button_to vote_comment_path(comment, value: "yes"), <%= button_to vote_in_favor_against_path("yes"),
method: "post", method: "post",
remote: can?(:vote, comment), remote: can?(:create, comment.votes_for.new(voter: current_user)),
"aria-pressed": pressed?("yes"), "aria-pressed": pressed?("yes"),
title: t("votes.agree") do %> title: t("votes.agree") do %>
<span class="show-for-sr"><%= t("votes.agree") %></span> <span class="show-for-sr"><%= t("votes.agree") %></span>
@@ -14,9 +14,9 @@
</span> </span>
<span class="against"> <span class="against">
<%= button_to vote_comment_path(comment, value: "no"), <%= button_to vote_in_favor_against_path("no"),
method: "post", method: "post",
remote: can?(:vote, comment), remote: can?(:create, comment.votes_for.new(voter: current_user)),
"aria-pressed": pressed?("no"), "aria-pressed": pressed?("no"),
title: t("votes.disagree") do %> title: t("votes.disagree") do %>
<span class="show-for-sr"><%= t("votes.disagree") %></span> <span class="show-for-sr"><%= t("votes.disagree") %></span>

View File

@@ -16,4 +16,8 @@ class Comments::VotesComponent < ApplicationComponent
false false
end end
end end
def vote_in_favor_against_path(value)
comment_votes_path(comment, value: value)
end
end end

View File

@@ -0,0 +1,26 @@
module Comments
class VotesController < ApplicationController
load_and_authorize_resource :comment
before_action :authenticate_user!
before_action :verify_comments_open!
def create
authorize! :create, Vote.new(voter: current_user, votable: @comment)
@comment.vote_by(voter: current_user, vote: params[:value])
respond_to do |format|
format.js { render :show }
end
end
private
def verify_comments_open!
return if current_user.administrator? || current_user.moderator?
if @comment.commentable.respond_to?(:comments_closed?) && @comment.commentable.comments_closed?
redirect_to polymorphic_path(@comment.commentable), alert: t("comments.comments_closed")
end
end
end
end

View File

@@ -1,8 +1,8 @@
class CommentsController < ApplicationController class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create, :hide, :vote] before_action :authenticate_user!, only: [:create, :hide]
before_action :load_commentable, only: :create before_action :load_commentable, only: :create
before_action :verify_resident_for_commentable!, only: :create before_action :verify_resident_for_commentable!, only: :create
before_action :verify_comments_open!, only: [:create, :vote] before_action :verify_comments_open!, only: [:create]
before_action :build_comment, only: :create before_action :build_comment, only: :create
load_and_authorize_resource load_and_authorize_resource
@@ -27,11 +27,6 @@ class CommentsController < ApplicationController
end end
end end
def vote
@comment.vote_by(voter: current_user, vote: params[:value])
respond_with @comment
end
def flag def flag
Flag.flag(current_user, @comment) Flag.flag(current_user, @comment)
set_comment_flags(@comment) set_comment_flags(@comment)

View File

@@ -82,7 +82,7 @@ module Abilities
unless user.organization? unless user.organization?
can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate" can [:create, :destroy], ActsAsVotable::Vote, voter_id: user.id, votable_type: "Debate"
can :vote, Comment can :create, ActsAsVotable::Vote, voter_id: user.id, votable_type: "Comment"
end end
if user.level_two_or_three_verified? if user.level_two_or_three_verified?

View File

@@ -1,8 +1,9 @@
resources :comments, only: [:create, :show] do resources :comments, only: [:create, :show] do
member do member do
post :vote
put :flag put :flag
put :unflag put :unflag
put :hide put :hide
end end
resources :votes, controller: "comments/votes", only: :create
end end

View File

@@ -0,0 +1,15 @@
require "rails_helper"
describe Comments::VotesController do
let(:comment) { create(:comment) }
describe "POST create" do
it "allows voting" do
sign_in create(:user)
expect do
post :create, xhr: true, params: { comment_id: comment.id, value: "yes" }
end.to change { comment.reload.votes_for.size }.by(1)
end
end
end

View File

@@ -113,7 +113,8 @@ describe Abilities::Common do
describe "Comment" do describe "Comment" do
it { should be_able_to(:create, Comment) } it { should be_able_to(:create, Comment) }
it { should be_able_to(:vote, Comment) } it { should be_able_to(:create, user.votes.build(votable: comment)) }
it { should_not be_able_to(:create, another_user.votes.build(votable: comment)) }
it { should be_able_to(:hide, own_comment) } it { should be_able_to(:hide, own_comment) }
it { should_not be_able_to(:hide, comment) } it { should_not be_able_to(:hide, comment) }

View File

@@ -8,6 +8,7 @@ describe "Abilities::Organization" do
let(:organization) { create(:organization) } let(:organization) { create(:organization) }
let(:debate) { create(:debate) } let(:debate) { create(:debate) }
let(:proposal) { create(:proposal) } let(:proposal) { create(:proposal) }
let(:comment) { create(:comment) }
it { should be_able_to(:show, user) } it { should be_able_to(:show, user) }
it { should be_able_to(:edit, user) } it { should be_able_to(:edit, user) }
@@ -22,7 +23,7 @@ describe "Abilities::Organization" do
it { should_not be_able_to(:vote, Proposal) } it { should_not be_able_to(:vote, Proposal) }
it { should be_able_to(:create, Comment) } it { should be_able_to(:create, Comment) }
it { should_not be_able_to(:vote, Comment) } it { should_not be_able_to(:create, user.votes.build(votable: comment)) }
it { should_not be_able_to(:read, SDG::Target) } it { should_not be_able_to(:read, SDG::Target) }