Is there a better way to access CanCanCan's methods such as can? in a model?

33 views Asked by At

CanCanCan’s methods are only available in a controller or view, but I want to access them in a model, more specifically in a model’s save method. The workaround I use for this is the following: I create an attr_accessor :ability in the model and assign an Ability object to it in the controller before I call save.

class Example
  include ActiveModel::Model

  attr_accessor :ability

  def save
    if ability.can?(:create, SomeOtherModel)
       ...
    end
  end

end
class ExamplesController < ApplicationController
  def create
    @example = Example.new(params[:example])
    @example.ability = Ability.new(current_admin_user) #note: current_admin_user can be several separate models such as Admin, Support

    if @example.save
      ...
    end
  end

end

Is there a better method to call can? from within a model? Are there any problems with this solution, from a security standpoint or otherwise?

1

There are 1 answers

0
Thanh On

You can also add an ability method in your model and delegate the can? method:

# app/models/user.rb
class User
  delegate :can?, :cannot?, to: :ability

  def ability
    @ability ||= Ability.new(self)
  end
end

some_user.can? :update, @article

https://github.com/CanCanCommunity/cancancan/blob/develop/docs/define_check_abilities.md

With this solution, I think you will need to define ability method in all your models that need to check ability, so it can have duplicated code.

From security standpoint, it can lead to unexpected things. Controllers already support strong parameters to create/update only permitted attributes of model.

For example, if Support only can update some attributes and Admin can update all attributes, how do you control that in your model?

And If you check ability in controller, it can prevent actions of user and avoid doing unnecessary queries to server.

So I think that why CanCan recommends that can method works best in controllers and views

https://github.com/CanCanCommunity/cancancan/blob/develop/docs/controller_helpers.md