Rails like and unlike posts I have the following two methods which handle the liking and unliking of posts in my Rails application:

def create
  @post = Post.find(params[:id])
  if @post.present?
    @like = Like.new(user_id: current_user.id, post_id: @post.id)
    if @like.save
      redirect_to post_redirect(@post), :notice =&gt; 'Liked!'
    else
      redirect_to post_redirect(@post), :alert =&gt; 'An error prevented you from liking this post!'
    end
  else
    redirect_to post_redirect(@post), :alert =&gt; 'Invalid post!'
  end
end

def destroy
  @post = Post.find(params[:id])
  if @post.present?
    @like = Like.where(user_id: current_user.id, post_id: @post.id).first
    if @like.destroy
      redirect_to post_redirect(@post), :notice =&gt; 'Unliked!'
    else
      redirect_to post_redirect(@post), :alert =&gt; 'An error prevented you from unliking this post!'
    end
  else
    redirect_to p, :alert =&gt; 'Invalid post!'
  end
end


They both check that the post exists first and then creates or destroys the like record containing the post id and user id and redirects to the post with a message depending on the outcome.

In the Like model I prevent duplicate likes with: validates :user_id, uniqueness: {scope: :post_id}

However the methods feel quite bloated... is there a better way to handle this?
You're right. The code can be improved. Here is how I'd write this.


We can extract post lookup into a method or before hook.
There is no need to check if Post was found. In production environment find will raise an ActiveRecord::RecordNotFound exception (I'm assuming you're using AR)
The destroy action can be a little more optimistic. When somebody unlikes the post, which cannot be found or which is not liked, we can just show the success. After all there is no like for the post.
We can use associations on models to write less.
AR understands relations in conditions. where(user: current_user) instead of where(user_id: current_user.id)
Use find_by instead of where().first


For example:

class LikesController &lt; ApplicationController
  # before_action :find_post

  def create
    if post.likes.create(user: current_user)
      redirect_to post_redirect(post), :notice =&gt; 'Liked!'
    else
      redirect_to post_redirect(post), :alert =&gt; 'An error prevented you from liking this post!'
    end
  end

  def destroy
    post.likes.where(user: current_user).destroy_all
    redirect_to post_redirect(post), :notice =&gt; 'Unliked!'
  end

  private

  def post
    @post ||= Post.find(params[:id])
  end

  # def find_post
  #   @post = Post.find(params[:id])
  # end
end