Passing params to CanCan in RoR
Asked Answered
A

3

9

I have a controller with a method like;

def show

    if params[:format].eql?("pdf")
    // do something
    elsif params[:format].eql?("csv")
    // do something
    end
end

But i have users with different roles. So i use CanCan to manage access control. Now i want X role can do the action show in controller iff params[:format].eql?("csv")

I think it can be like ;can :show, resource if params[:format].eql?("csv"). So how can i send parameters to ability.rb?

Any idea?

Thanks.

Admixture answered 27/2, 2012 at 21:4 Comment(0)
C
30

In ApplicationController add the following:

# CanCan - pass params in to Ability
# https://github.com/ryanb/cancan/issues/133
def current_ability
  @current_ability ||= Ability.new(current_user, params)
end
Coveney answered 27/2, 2012 at 21:51 Comment(1)
Perfect - except indented by 4 spaces :DJehad
W
8

The most current answer is in the CanCan wiki: https://github.com/ryanb/cancan/wiki/Accessing-Request-Data

Williamwilliams answered 6/5, 2012 at 3:51 Comment(0)
T
1

can takes two arguments: first is type of action that user is trying to perform on a resource, second is resource (can be class name or instance variable) itself. If you have your Ability set correctly, you should be able to do something like this:

def show
  if params[:format].eql?("pdf")
    // do something
  elsif params[:format].eql?("csv")
    if can? :read, resource
      #do stuff
    end
  end
end

Don't forget that you have to have your user authenticated before running any CanCan checks. can? method only returns true or false. I normally like to use authorize! method to check abilities. Unlike can, it would rise CanCan::AccessDenied error that you can rescue and process gracefully. Something in the lines of:

#models/ability.rb
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? :hiring_manager
      can [:read, :update], Post, user_id: user.id
    end
  end
 end

#controllers/posts_controller.rb
class PostsController < ApplicationController::Base
  before_filter :authenticate_user

  def show
    @post = Post.find(params[:id])
    authorize! :read, @post # will thorow an exception if not allowed
  end
end 

Then, I just catch the exception on ApplicationController level.

Toluate answered 27/2, 2012 at 22:1 Comment(1)
well nice example Simon but it is not what i am looking for. Because i just use params[:format] to decide behaviour of method. In your example you use params to find a record. The record passess to ability to decide access control. But im not using params in your way.Thyratron

© 2022 - 2024 — McMap. All rights reserved.