Reputation: 121
I'm trying to integrate pundit with my active admin and devise configuration. But the app works weirdly. It takes in model/record as current_user.
my policy file:
class AdminUserPolicy
attr_reader :current_user, :model
def initialize(current_user, model)
Rails.logger.info '--------------- initialize called-------------------'
Rails.logger.info current_user
Rails.logger.info model
@current_user = current_user
@record = model
end
def index?
@current_user.admin?
end
end
controller:
controller do
include Pundit
protect_from_forgery
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
before_action :authenticate_admin_user!
def index
authorize current_admin_user
super
end
private
def user_not_authorized
flash[:alert]="Access denied"
redirect_to (request.referrer || admin_root_path)
end
end
The log is as follows:
--------------- initialize called----------------------------------------
#<AdminUser:0x007f27733f8a80>
Completed 500 Internal Server Error in 364ms (ActiveRecord: 312.8ms)
NoMethodError (undefined method `admin?' for nil:NilClass):
app/policies/admin_user_policy.rb:13:in `index?'
app/admin/dashboard.rb:19:in `index'
Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (4.8ms)
Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.5ms)
Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.1ms)
Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (39.5ms)
The weird part is, according to logs, current_user=nil
and model=#<AdminUser:0x007f27733f8a80>
I swapped current_user with model my policy file as
def index?
@record.admin?
end
And it works! I don't understand this strange behaviour.
Upvotes: 1
Views: 976
Reputation: 3950
Pundit policy doc says that it calls the current_user
method to retrieve what to send into the first argument of the initialize
method inside the Policy class. If you have configured ActiveAdmin to retrieve the current logged in user by using current_admin_user
, then you have to override the pundit default method in your ApplicationController
class like so: Ref
class ApplicationController < ActionController::Base
// ...
def pundit_user
current_admin_user // or whatever based on ActiveAdmin initializer config
end
end
In order to make the defined policy working, you have to invoke authorize
inside the controller action with the instance of the corresponding policy model. So if you have a PostPolicy
and you want to authorize the update
action, you have to do the following:
controller do
def update
@post = Post.find(params[:id])
authorize @post // the current user will be automatically sent to the PostPolicy
super
end
end
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. In this case, you can imagine that authorize
would have done something like this:
unless PostPolicy.new(current_user, @post).update?
raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
end
Having all these, in your case, if you want that a user should be authorized before viewing the list of all users, you can define the AdminUserPolicy
like you have done already. Then in the index
action of your AdminUserController
,
controller do
def index
@users = AdminUser.all
authorize @users // NOT `authorize current_admin_user`
super
end
end
You can pass a second argument to authorize
if the name of the permission you want to check doesn't match the action name. For example:
def publish
@post = Post.find(params[:id])
authorize @post, :update?
@post.publish!
redirect_to @post
end
Upvotes: 1