David Rice
David Rice

Reputation: 208

Using CanCanCan, how do I authorize either/or in a controller?

I've got a page for administrating multiple objects (like users and groups), and I want to ensure that only users who have access to create at least one of those types of objects can view the page.

Basically, I want to be able to write something like

(authorize! :create, User) || (authorize! :create, Group)

Any suggestions?

Upvotes: 4

Views: 907

Answers (2)

Marlen T. B.
Marlen T. B.

Reputation: 884

The best I can come up with is to use multiple can? statements and raise AccessDenied on failure. You also should avoid authorization checks against a model class, and instead authorize against a model instance. See CanCanCan - Common Mistakes.

user = User.new(...)
group = Group.new(...)
raise CanCan::AccessDenied.new(nil, :create, [user, group]) \
  unless can?(:create, user) || can?(:create, group)

AccessDenied.new(nil, ..) -> nil for the first argument result in the default error message. See cancan/exceptions.

I'd probably move this into a helper to a method named def authorize create_group_or_user!

That said, maybe you are doing too much in this controller? Alternatively, you could make this controller redirect without authorization to the appropriate GroupController or UserController, and perform the appropriate authorization checks in those locations.

Alternate Option 2: Maybe use an accessible_by restriction on the content, and don't call authorize! at all.

Upvotes: 0

Abs
Abs

Reputation: 3962

One way to achieve this is by mixing

load_and_authorize_resource :user
load_and_authorize_resource :through => :user

this is a convenience helper for calling authorize on all resources in a controller that does something like this:

class GroupsController < ActionController::Base
  load_and_authorize_resource
  load_and_authorize_resource :through => :user

  def create
    # Automatically does the following:
    # @group = Group.find(group_params[:id])
    # authorize! :create, @group

    # @user= User.find(group_params[:user_id])
    # authorize! :create, @user
  end

end

so where in your controller you load the Group and User objects it will auto authorize them against your rules/Abilities like

can [:create], [User, Group]

Of course you will need your Groups to be a nested resource:

resources :users do
  resources :groups
end

Hope it helps.

Upvotes: 0

Related Questions