I am trying to make an app with Rails 4.
I have defined a series of roles with Rolify gem.
Now, I want to use pundit to allow users with a role to do certain things. Where more than one type of role can do a thing, I have defined a group of roles.
In my application_policy, I have defined private methods which set out the groups of roles that I want to use in the pundit permissions.
My application policy instantiates user and record. I then define record as the name of the relevant model (the same name as the policy for that model).
I have:
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
scope
end
end
private
def cf_legal
[ :Admin, :CF_Legal, :CF_Policy_Manager ]
end
def cf_content
[ :Admin, :CF_Author, :CF_Editor ]
end
end
Then in my content policy, I want to say:
def record
content
end
def create
user.has_role? :cf_content
end
When I save this and try it, I can't see the thing that I am supposed to see (as a user with the role Author.
Can anyone see how to do this?
tl;dr: Use query methods on your Policy class.
First, the model should have it's own Policy class that (optionally) extends your ApplicationPolicy class. Let's say your model is called Post
. Then you could do something like:
class PostPolicy < ApplicationPolicy
attr_reader :user, :post
def initialize(user,post)
@user = user
@post = post
end
def create?
cf_content.all? { |role| user.has_role?(role) }
end
private
def cf_content
[ :Admin, :Author, :Editor ]
end
end
class PostsController
def create
@post = Post.new(params[:post])
authorize @post, :create?
# @post.save and redirect, etc.
end
end
And the authorize call will invoke the create?
query method and check if the user has the roles in cf_content.
You may not even need to add the second argument, create?
, as the pundit documentation says:
The authorize method automatically infers that Post will have a matching PostPolicy class, and instantiates this class, handing in the current user and the given record. It then infers from the action name, that it should call update? on this instance of the policy.
Or in your case, create?
instead of update?
.
You can check for multiple roles like this :
user.admin? or user.author?
If you want to check for role from an array you can also check with : cf_content.include?(user.role) OR cf_content.include?(user.role.title) whichever suits the scenairio.
You can also check for instance bound roles with -> user.applied_roles and see if the roles it returns includes your expected role.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With