jävi
jävi

Reputation: 4565

Check object belongs to current_user in Controller (has_and_belongs_to_many)

I'm using devise for authentification, so I have a current_user in every controller. My models are:

class User < ActiveRecord::Base
    has_many_and_belongs_to :posts
end

class Posts < ActiveRecord::Base
    has_many_and_belongs_to :users
end

class PostsController < ApplicationController
    before_filter :authenticate_user!

    def show
        @post = Post.find(params:id)
        # need to check if @post belongs to current_user here
        # ...
    end

    def edit
        @post = Post.find(params:id)
        # need to check if @post belongs to current_user here
        # ...
    end
end

Some of the actions in PostsController (for instance show and edit) need to check if the Post fetched from the DB belongs to the current_user. If it doesn't, I want to show a 404 error and end the execution (just after the find call).

Obviously I would like to stay DRY, so I don't want to write the same code in every action.

I've tried to write a private method in PostsController, however from a private method I cannot redirect to a 404 and then interrupt the execution immediately.

A before_filter won't work since I would be executed before each action, and I need the @post object which is being fetched inside each action.

Finally I don't want to use additional gems like CanCan.

Upvotes: 1

Views: 2767

Answers (3)

Sandip Ransing
Sandip Ransing

Reputation: 7733

controller code

class PostsController < ApplicationController
  before_filter :authenticate_user!
  before filter :load_post, :only => [:edit, :update, :show]

  private
  def load_post
    @post = current_user.posts.find_by_id(params[:id)
    @post ||= invalid_url! # defined in app controller 
  end
end

Upvotes: 0

Chris Barretto
Chris Barretto

Reputation: 9529

How about writing a private method that returns a boolean and redirecting in your main method based off of the return value?

class PostsController < ApplicationController
    before_filter :authenticate_user!

    def show
        redirect_to 404 if !check_my_stuff?
        # need to check if @post belongs to current_user here
        # ...
    end

    def edit
        redirect_to 404 if !check_my_stuff?
        # need to check if @post belongs to current_user here
        # ...
    end

    private

    def check_my_stuff?
      @post = Post.find_by_id(params:id)
      (@post.user == current_user) ? true : false
    end
end

Upvotes: 0

Robin Clowers
Robin Clowers

Reputation: 2160

I have not tested this, but you should be able to do something like this:

class Post < ActiveRecord::Base
  has_many_and_belongs_to :posts

  scope :for_user, lambda { |user| joins(:users).where("user_id = ?", user.id)
end

Then in your controller:

Post.for_user(user).find(params[:id])

That way the logic is not repeated and it's reusable.

Upvotes: 2

Related Questions