Kris
Kris

Reputation: 133

DRY voting methods

I have a prompt asking to write my up_vote and down_vote methods in only two lines using 'redirect_to' and the 'update_vote!' method as presented below. Implementing redirect_to is easy enough, but I'm not quite sure how to write my up/down_vote methods concisely using the existing 'update_vote!' method. Any help is appreciated.

 class VotesController < ApplicationController
      before_action :load_post_and_vote

      def up_vote

        if @vote
          @vote.update_attribute(:value, 1)
        else
          @vote = current_user.votes.create(value: 1, post: @post)
        end

        # http://apidoc.com/rails/ActionController/Base/redirect_to
        redirect_to :back
      end

      def down_vote

        if @vote
          @vote.update_attribute(:value, -1)
        else
          @vote = current_user.votes.create(value: -1, post: @post)
        end

        # http://apidoc.com/rails/ActionController/Base/redirect_to
        redirect_to :back
      end

      private

      def load_post_and_vote
        @post = Post.find(params[:post_id])

        @vote = @post.votes.where(user_id: current_user.id).first
      end

      def update_vote!(new_value)
        if @vote
          authorize @vote, :update?
          @vote.update_attribute(:value, new_value)
        else
          @vote = current_user.votes.build(value: new_value, post: @post)
          authorize @vote, :create
          @vote.save
        end
      end
    end

Upvotes: 0

Views: 87

Answers (2)

Kris
Kris

Reputation: 133

seems that answer was easy enough =]

def up_vote
  update_vote(1)
  redirect_to :back
end

def down_vote
  update_vote(-1)
  redirect_to :back
end

Upvotes: -1

Arup Rakshit
Arup Rakshit

Reputation: 118289

You should invoke the update_vote! method. How about:

def up_vote        
  update_vote!(1)
  # http://apidoc.com/rails/ActionController/Base/redirect_to
  redirect_to :back
end

def down_vote
    update_vote!(-1)
    # http://apidoc.com/rails/ActionController/Base/redirect_to
    redirect_to :back
end

Also your method can be re-written as :

def update_vote!(new_value)
  Vote.find_or_create_by post: @post do |v|
    authorize v, :update?
    v.user_id = current_user.id
    v.value = new_value
    v.save!
  end
end

Read find_or_create_by.

Upvotes: 2

Related Questions