What is the correct way to authorize and check abilities for a namespaced, model-less controller using CanCanCan?
After much googling and reading the wiki, I currently have
#controllers/namespaces/unattacheds_controller.rb
def Namespaces::UnattachedsController
authorize_resource class: false
def create
# does some stuff
end
end
#models/ability.rb
def admin
can [:create], :namespaces_unattacheds
end
#view/
<%= if can? :create, :namespaces_unattacheds %>
# show a create form to authorized users
<% end %>
This is not correctly authorizing the controller. Admins can see the conditional create form, but are not authorized to post to the create action.
post :create, valid_params
Failure/Error: { it { expect( flash ).to have_content "Successfully created" }
expected to find text "Successfully created"
got: "You are not authorized to access this page."
In one example, the wiki suggests creating a separate Ability class for a namespaced controller. https://github.com/CanCanCommunity/cancancan/wiki/Admin-Namespace
Is there a simpler way to achieve this? This app uses many namespaced controllers, I don't really want to create an ability class for each one.
Is there correct syntax to refer to the namespaced controller in the Ability class?
can [:create], Namespaces::Unattacheds
can [:create], :namespaces_unattacheds
can [:create], namespaces/unattacheds
????
Adding an answer because this question seems to be getting a reasonable number of visitors. Hope it can help someone.
I received some good suggestions here, that helped me think through my problem. Ultimately I realised that I was fighting against CanCanCan's conventions with what I was trying to achieve.
I swapped to Pundit, which allowed me to authorise an object in the controller while referring to a specific policy class. Something like
# Admin::UserController
def update
authorize @user, policy_class: Admin::UserPolicy
end
# UserController
def update
authorize @user, policy_class: UserPolicy
end
Combined with strong params defined on the controller, I was able to ensure that only specific attributes could be updated.
This won't work for everyone. For example, this approach would not prevent admins from updating all a user's attributes if they bypass the controller (e.g., via the console). But it worked for my situation.