How can I allow a user to only visit their own show page using cancan?
Asked Answered
R

2

7

I've been going through the railscast on using the cancan gem but am stuck on how to only allow a user to visit their own show page.

My code looks like this:

Ability model

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.role == "admin"
      can :manage, :all
    else
      can :read, :all
      if user.role == "author"
        can :create, Review
        can :update, Review do |review|
          review.try(:user) == user
        end
        can :update, User do |user|
          user.try(:current_user) == current_user
        end
      end
      if user.role == "owner"
        can :update, Venue
      end
    end
  end
end

User controller

class UsersController < ApplicationController
  load_and_authorize_resource
end

A user (author) can only update their own reviews, but can currently view all users show pages by altering the URL.

What am I missing here?

Rooke answered 12/6, 2011 at 18:15 Comment(1)
The problem is in the line can :read, :all. You allowed viewing all pages to all users.Ofilia
L
11

Constraints can be passed right in your ability class, even easier than the way you're trying. I'm sure this is missing some abilities you're looking to have, but this should get you started. I'm assuming Reviews :belong_to Users with a foreign key of :user_id. It also looks like you need some similar kind of constraint for Venues, but you didn't have it in your code so I didn't put it in this.

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.role == "admin"
      can :manage, :all
    elsif user.role == "author"
      can :create, Review
      can :update, Review, :user_id => user.id
      can [:show, :update], User, :id => user.id
    elsif user.role == "owner"
      can :update, Venue
      can [:show, :update], User, :id => user.id
    else
      can [:show, :update], User, :id => user.id
    end
  end
end
Lindholm answered 12/6, 2011 at 18:37 Comment(0)
H
0

Try adding a check in the controller for when a request comes in for /show to check that the current_user is the owner of the page/profile. Something along the lines of:

def show
  @user = User.find(params[:id])
  #show_page unless current_user.id != @user.id
end

Maybe flash a notice that "You don't own that page" or something similar on failure.

Haun answered 12/6, 2011 at 18:22 Comment(1)
No need to do that. CanCan do all this stuff for you.Ofilia

© 2022 - 2024 — McMap. All rights reserved.