Ryan Bigg

⟵ Posts

A Sense of Belonging

29 Aug 2008

Numerous times I’ve needed and I’ve seen other people have needed the need to check whether an object belongs to the currently logged in user. I’ve worked out that something like this works:

class User < ActiveRecord::Base
  has_many :posts
  def owns?(object)
    object.user == self
  end
end

This works when you have a currently logged in user and call it by using current_user.owns?(@post). Now what if you wanted to do it the other way around? Well it’s really as simple as this:

class Post < ActiveRecord::Base
  belongs_to :user
  def belongs_to?(other_user)
    user == other_user
  end
end

Now you can reference that through @post.belongs_to?(other_user).

If you wanted to use either of these in the controller, it would be like this:

class PostsController < ApplicationController
  def edit
    @post = Post.find(params[:id])
    check_ownership
  end

  def update
    @post = Post.find(params[:id])
    if current_user.owns?(@post) # or @post.belongs_to?(current_user)
    # carry on...
      if @post.update_attributes(params[:post])
        flash[:success] = "Post updated!"
        redirect_to topic_path(@topic)
      else
        flash[:error] = "Post could not be updated."
        render :action => "edit"
      end
    else
      flash[:error] = "You do not own that post."
    end
  end

  private
    def check_ownership
      if !current_user.owns?(@post) # or @post.belongs_to?(current_user)
        flash[:error] = "You do not own that post!"
        redirect_back_or_default topic_path(@topic)
      end
    end
end

Now here we’ve called check_ownership in the edit action which will stop the template from being rendered by calling redirect_back_or_default. We can’t call (as I found out thanks to Blue_Sea) check_ownership in the same way in the update action because the code will still be executed. So we must call the methods we defined in the model, either current_user.owns?(@post) or @post.belongs_to?(current_user).