NoMethodError undefined method `admin?' for nil:NilClass Pundit, Devise Rails - devise

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.

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

Related

Rails3 + Devise + Sign_in + Controller

i have a simple controller where i want to log user manually and for some reason devise method sign_in is not working
Here is my controller:
class Brand::ChallengesController < ApplicationController
def sign_in
user = User.find_by_email(params[:email])
if user and user.valid_password?(params[:password])
sign_in(:user, user)
redirect_to brand_challenges_url
else
...
end
end
...
edit :
I always get this answer on the sign_in method:
wrong number of arguments (2 for 0)
It seems that i only can use this method within a devise child class.
I tried to include many Devise helpers but nothing it working for the moment.
def sign_in
user = User.find_by_email(params[:email])
if user and user.valid_password?(params[:password])
sign_in(:user, user)
^^^^^^^
See that line.
You are calling sign_in - which is the name of method that you just wrote.
Which means your code is calling itself... and your sign_in method has zero parameters.
(If you took away the (:user, user) part... you'd actually get a stack overflow - because your code would call itself... which would call itself... over and over until the memory just exploded and died).
Are you trying to call some other method called sign_in ? if so - where is that method located?

Devise: the method resource is not called properly

I am using devise. In a view partial, I have:
<%= simple_form_for resource, :as => :user, ...
In my application helper:
# #see http://stackoverflow.com/questions/4541075/what-is-the-devise-mapping-variable-and-how-can-i-include-it
def resource_class
devise_mapping.to
end
# #see http://stackoverflow.com/questions/4081744/devise-form-within-a-different-controller
def resource_name
:user
end
def resource
# with some controllers (homepage, static, this method is called)
# with other controllers (Item, it's not called: I don't see the abort call)
abort('should stop here')
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
On some controllers, my form works fine. On others, I get this error:
Couldn't find Item without an ID
The problem is that the method I have defined is not called. With some controllers, ApplicationHelper.resrouce is called, on others, it's an other method resource (Item.resource ?), and I don't know where it's defined.
How the method resource can be defined elsewhere ? Why is the method resource of my application helper not called on certain pages ?
Note: I am using the gem inherited_resources that defines the method resource. Maybe this create the conflict. But I don't know how the method is inherited
After seeing http://railscasts.com/episodes/230-inherited-resources, it all became clear.
I defined resource in ItemsController:
class ItemsController < InheritedResources::Base
# #see http://stackoverflow.com/questions/16831095/devise-the-method-resource-is-not-called-properly
def resource
# this solves my problem. It looks super wrong tough
#resource ||= User.new
#view_context.resource # tried that, but doesn't work
end
# ...
And now it works. The method resource was being re-defined by the gem for that controller...

can't find method in application controller

I've been trying to get authentication working with devise, and then omniauth, but I haven't been able to get the user session.
In my application controller, I have
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
which I got from the updated railscast https://github.com/railscasts/241-simple-omniauth/blob/master/revised/blog-after/app/controllers/application_controller.rb
In my app, I call
<% if current_user %>
but this always errors out as undefined local variable or method 'current_user'
why is this? is it a problem with my application controller, or maybe a session error with rails?

devise+omniauth devise helper like current_user,user_signed_in? not working

I am using devise and create login with Facebook using omniauth, but having problem of lost the devise helper methods access like current_user and user_signed_in? methods are not working.
EDIT
AuthenticationController
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
redirect_to USercontroller dashboard method
UserController
before_filter :logged_in
def dashboard
#user = User.find(params[:id])
#comment = Comment.new
#comments = #user.comments.all.paginate(:page => params[:page], :per_page => 5)
end
so here control should go to dashboard method after checking logged_in method in ApplicationController
logged_in method in ApplicationController
Application Controller
def logged_in
if user_signed_in?
return true
else
redirect_to root_path
flash[:message] = "please login"
end
end
when I logged in using facebook following code generated at console
Started GET "/users/52/dashboard" for 127.0.0.1 at Thu Mar 29 12:51:55 +0530 2012
Processing by UsersController#dashboard as HTML
Parameters: {"id"=>"52"}
Redirected to http://localhost:3000/
Filter chain halted as :logged_in rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)
in the above code control is render from logged_in method to root_path but it shold render dashboard_path
So I am guessing User_signed_in? helper is not working I also use current_user in stead of that generate same error
As I see, user_signed_in? is working, but returns false, as for Devise user is not logged in. To fix this, just replace the session id storing with Devise sign_in method in your controller action:
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
sign_in(:user, user)
# actually if you really really need that id in the session, you can leave this line too :)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
After creating the user account via Facebook, how do you sign in the user?
You should still be using devise helpers like sign_in_and_redirect. Something like:
user = User.build_from_omniauth(omniauth)
if user.save
sign_in_and_redirect(:user, user)
end
Then you should be able to use helpers like current_user and user_signed_in? (which just check if current_user is not nil).
Taking a look at your edit, my answer is still valid. What you need to do is use sign_in_and_redirect(:user, user) instead of just setting the id in the session.
You can easily customize where the user is redirected after sign in with devise.
Another thing, remove this logged_in filter, Devise has a authenticate_user! method that you can use as a before_filter. It will redirect the user to the sign in page, and when they login, it will redirect them to the page they were trying to access.
You're using Devise, so try to take advantage of that, and go read the doc ;)

declarative_authorization Authorization.current_user error

I have authlogic set up and want to use declarative_authorization. In Ryan Bates's railcast #188 he uses
before_filter {|c| Authorization.current_user = c.current_user}
If I do the same I get an error:
`private method 'current_user' called for #<UsersController:0xa6025e8>`
The current_user method is in application controller and is private (as in the Authlogic setup example) and if I make it public, this works. It also works if I just say current_user (current_user method is also a helper) instead of c.current_user in the before filter block.
So would it actually be ok if I would just do before_filter {Authorization.current_user = current_user}?
Try this:
application_controller.rb
Add before_filter :set_current_user
Put this method into protected
def set_current_user
Authorization.current_user = current_user
end