Passing params to CanCan in RoR

2020-07-09 13:38发布

问题:

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.

回答1:

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


回答2:

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



回答3:

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.