-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Authorizing controller actions with no associated model #77
Comments
Great question, Patrick. @jnicklas, what would you do? |
Why not depend on the Controller name? Like, having a HomePolicy class which just takes a single argument, the User, then manually retrieve the policy and check against it. If that's too "manually" and you want to use the #policy helper, why not inject |
@thomasklemm @tbuehlmann I've played around with that idea (using a custom helper method) but then you have a mixture of policies for controllers and models and things get confusing quickly. This also goes against the single responsibility principle. I'm leaning towards implementing action authorization using separate custom code in my app and Pundit for all the models. Again, any help would be appreciated. |
I just ran into this problem. I have a HomeController that has 3 actions and no associated model. The second argument passed to authorize is necessary to find the policy class it needs to make the decision on whether or not the action is authorized, so I just passed it self and changed the filename and class name to reflect the controllers name. Here is my policy class: (home_controller_policy.rb)
And in the controller I pass in self as the second argument, like this:
It works well for me. I don't mind having only one policy being associated with just a controller. It's clean, clear, and functions. |
I guess we could support passing in symbols to authorize(:home, :show?) And then we could have a policy: class HomePolicy
def initialize(user)
@user = user
end
def show?
end
end But we need to be careful with the argument parsing, since we already have locked ourselves a bit in, and we also have many suggestions for extras like custom error messages and additional arguments. |
I think something like @jnicklas is suggesting would be worthwhile. This would allow apps to keep authorization logic in one place. I've yet to have an app where all authorizations are based on a model. This is especially apparent when authorization logic is more complex because of multiple roles. What about authorizations like this in a controller: class PostsController < ApplicationController
def special
authorize :posts, :special?
or
authorize :posts # infers action name?
or
authorize # infers class and action names?
end
def create
authorize @post, :create?
or
authorize @post # infers action name
end
end |
Might be more overhead than makes sense, but since there are two pretty distinct cases for policies why not give each it's own base class. UserPolicy < Pundit::ModelPolicy
# Looks for model named User.
end
PagePolicy < Pundit::ControllerPolicy
# Looks for a controller named PagesController.
end Just a thought. |
Pundit does not have base classes. |
Maybe a configuration to overload the |
We could pass in a policy explicitly to authorize: class HomeController < ApplicationController
def show
authorize(nil, :show?, policy: HomePolicy) # Will work too if there's a record passed in
end
end Related to #12. |
I hope you guys think of something soon because this functionality is extremely important to have and very common. For now @bradwheel's snippet seems to work though. |
|
Another example is an errors controller. I want to authorize anyone access to the show action in that controller. But, the controller doesn't have a model. So, Im hacking it together. |
I'd be pretty much happy about a solution. jnicklas' symbols solution sounds good to me. |
This would also be a great fix for multi-tenant apps: around_action :scope_current_company I get a def current_company
current_user.company
end
helper_method :current_company
def scope_current_company
Company.current_id = current_company.try(:id)
yield
ensure
Company.current_id = nil
end |
I highly recommend changing the |
@thomasklemm +1! |
Has this functionality been added? It would make a few things a lot easier! |
Headless policies have been implemented in #168. This feature has not yet been released in an official gem version though, so you'll have to reference the github source in you # Gemfile
gem 'pundit', github: 'elabs/pundit' |
Is this feature is available in current gem version? Seems for me it doesn't work properly. |
Yes, it is. Maybe you'd need to restart your Rails server to pick up the changes or have a typo either in the file name or class name. Could you check that? |
I double checked that, there is no typo and of course I restarted server couple times. It's so simple so I have no idea where I screwed up.
dashboard_policy.rb
my root path is 'dashboard#index' so when I start my application I get beautiful |
Is it Check this out:
|
sorry, policy is in the app/policies/ of course |
Please try to leave only this as your policy: class DashboardPolicy < Struct.new(:user, :dashboard)
def index?
true
end
end |
Interesting, in this case I get |
|
And I can't inherit from ApplicationPolicy because I have no model, but scope is needed for work at the same time. I'm confused |
Just say |
Still got |
I figured out what was wrong with my code. |
Pundit looks great for authorizing models but in some instances I need to authorize controller actions (with no associated model) as well. A simple check whether the user is logged in or not will suffice most of the time. However, sometimes the ability to view a controller action is based on a user role, i.e. user can view settings page if administrator but not if regular user.
What are the best practices for these situations? Any clarifications would be appreciated on how all the authorization pieces fit together.
The text was updated successfully, but these errors were encountered: