Hadir provides an authorization system like Pundit. With Hadir you separate policy logics and put them in policy classes based on each controller.
All you need is adding hadir
to your Gemfile:
gem 'hadir'
Hadir is focused on policy classes. You need a policy class for each controller and a method into it for each action (It's possible to use same method for multiple actions).
In the following controller we prevent to update or delete unpublished post, also in delete action we use custom method and messsage:
class Api::V1::PostsController < ActionController::Base
def update
post = Post.find(params[:id])
authorize post
end
def delete
post = Post.find(params[:id])
authorize post, 'update?', message: 'You are not allowed to delete unpublished post.'
end
private
def current_user
# retrieve current-user and return it
end
end
Following policy class will allow updating a post if it is not unpublished:
class Api::V1::PostsPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def update?
record.published?
end
end
Hadir makes following assumptions about your policy classes:
- Policy class name is the same as resource part of controller with
Policy
suffix. - Policy class has the same namespace as contoller class.
- The first argument is a user. In your controller, Hadir will call the
current_user
method to retrieve what to send into this class. (null
is acceptable) - The second argument is an object which you want to check its authorization. It can be any object you want.
- As a default behaviour Hadir maps your action to the method with the same name and question mark (
?
) as a suffix. For example Hadir mapsupdate
action toupdate?
method in your policy class. It is also possible to send your desired method name as second argument ofauthorize
method.
In Pundit you create a policy class for each object's class(most of the time a model) and put methods into it for each controller's action, there are some disadvantages:
- You have only one policy class for different API versions or admin APIs(different controllers) for the same model(class). You will have a messy class!
- You are not able to have policy if you don't pass a specific object as argument of
authorize
method.