nathanl / authority

*CURRENTLY UNMAINTAINED*. Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.
MIT License
1.21k stars 67 forks source link

undefined method can for custom action #88

Closed codeboxanvo closed 9 years ago

codeboxanvo commented 10 years ago

I tried to add new custom action like this:

class UsersController < ApplicationController def registrant_info end end

next, i change config file authority.rb like this:

Authority.configure do |config| config.controller_action_map.merge!( :registrant_info => 'registrant' )

config.abilities.merge!( :registrant => 'registrantable' ) end

then, in file user_authorizer i added code like this:

class UserAuthorizer < ApplicationAuthorizer

def self.registrantable_by?(user) user.has_role?(Role::ROLES[:admin]) end

def registrantable_by?(user) user.has_role?(Role::ROLES[:admin]) end end

finally i go to browser: localhost:3000/users/10/registrant_info, I got the error "undefined method `can_registrant_info?' for nil:NilClass"

Logs console: NoMethodError (undefined method can_registrant_info?' for nil:NilClass): /home/vinh-phuc/.rvm/gems/ruby-2.1.1@4.1/bundler/gems/load_and_authorize_resource-a77cce9a1170/lib/load_and_authorize_resource.rb:307:inauthorize_resource' activesupport (4.1.1) lib/active_support/callbacks.rb:424:in block in make_lambda' activesupport (4.1.1) lib/active_support/callbacks.rb:143:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:143:in block in halting_and_conditional' activesupport (4.1.1) lib/active_support/callbacks.rb:149:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:149:in block in halting_and_conditional' activesupport (4.1.1) lib/active_support/callbacks.rb:149:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:149:in block in halting_and_conditional' activesupport (4.1.1) lib/active_support/callbacks.rb:149:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:149:in block in halting_and_conditional' activesupport (4.1.1) lib/active_support/callbacks.rb:149:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:149:in block in halting_and_conditional' activesupport (4.1.1) lib/active_support/callbacks.rb:166:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.1) lib/active_support/callbacks.rb:229:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:229:in block in halting' activesupport (4.1.1) lib/active_support/callbacks.rb:166:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.1) lib/active_support/callbacks.rb:166:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.1) lib/active_support/callbacks.rb:86:incall' activesupport (4.1.1) lib/active_support/callbacks.rb:86:in run_callbacks' actionpack (4.1.1) lib/abstract_controller/callbacks.rb:19:inprocess_action' actionpack (4.1.1) lib/action_controller/metal/rescue.rb:29:in process_action' actionpack (4.1.1) lib/action_controller/metal/instrumentation.rb:31:inblock in process_action' activesupport (4.1.1) lib/active_support/notifications.rb:159:in block in instrument' activesupport (4.1.1) lib/active_support/notifications/instrumenter.rb:20:ininstrument' activesupport (4.1.1) lib/active_support/notifications.rb:159:in instrument' actionpack (4.1.1) lib/action_controller/metal/instrumentation.rb:30:inprocess_action' actionpack (4.1.1) lib/action_controller/metal/params_wrapper.rb:250:in process_action' activerecord (4.1.1) lib/active_record/railties/controller_runtime.rb:18:inprocess_action' actionpack (4.1.1) lib/abstract_controller/base.rb:136:in process' actionview (4.1.1) lib/action_view/rendering.rb:30:inprocess' actionpack (4.1.1) lib/action_controller/metal.rb:195:in dispatch' actionpack (4.1.1) lib/action_controller/metal/rack_delegation.rb:13:indispatch' actionpack (4.1.1) lib/action_controller/metal.rb:231:in block in action' actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:80:incall' actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:80:in dispatch' actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:48:incall' actionpack (4.1.1) lib/action_dispatch/journey/router.rb:71:in block in call' actionpack (4.1.1) lib/action_dispatch/journey/router.rb:59:ineach' actionpack (4.1.1) lib/action_dispatch/journey/router.rb:59:in call' actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:676:incall' warden (1.2.3) lib/warden/manager.rb:35:in block in call' warden (1.2.3) lib/warden/manager.rb:34:incatch' warden (1.2.3) lib/warden/manager.rb:34:in call' rack (1.5.2) lib/rack/etag.rb:23:incall' rack (1.5.2) lib/rack/conditionalget.rb:25:in call' rack (1.5.2) lib/rack/head.rb:11:incall' actionpack (4.1.1) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.1.1) lib/action_dispatch/middleware/flash.rb:254:incall' rack (1.5.2) lib/rack/session/abstract/id.rb:225:in context' rack (1.5.2) lib/rack/session/abstract/id.rb:220:incall' actionpack (4.1.1) lib/action_dispatch/middleware/cookies.rb:560:in call' activerecord (4.1.1) lib/active_record/query_cache.rb:36:incall' activerecord (4.1.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:621:in call' activerecord (4.1.1) lib/active_record/migration.rb:380:incall' actionpack (4.1.1) lib/action_dispatch/middleware/callbacks.rb:29:in block in call' activesupport (4.1.1) lib/active_support/callbacks.rb:82:inrun_callbacks' actionpack (4.1.1) lib/action_dispatch/middleware/callbacks.rb:27:in call' actionpack (4.1.1) lib/action_dispatch/middleware/reloader.rb:73:incall' actionpack (4.1.1) lib/action_dispatch/middleware/remote_ip.rb:76:in call' actionpack (4.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:17:incall' actionpack (4.1.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in call' railties (4.1.1) lib/rails/rack/logger.rb:38:incall_app' railties (4.1.1) lib/rails/rack/logger.rb:20:in block in call' activesupport (4.1.1) lib/active_support/tagged_logging.rb:68:inblock in tagged' activesupport (4.1.1) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.1.1) lib/active_support/tagged_logging.rb:68:intagged' railties (4.1.1) lib/rails/rack/logger.rb:20:in call' actionpack (4.1.1) lib/action_dispatch/middleware/request_id.rb:21:incall' request_store (1.0.6) lib/request_store/middleware.rb:8:in call' rack (1.5.2) lib/rack/methodoverride.rb:21:incall' rack (1.5.2) lib/rack/runtime.rb:17:in call' activesupport (4.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:26:incall' rack (1.5.2) lib/rack/lock.rb:17:in call' actionpack (4.1.1) lib/action_dispatch/middleware/static.rb:64:incall' rack (1.5.2) lib/rack/sendfile.rb:112:in call' railties (4.1.1) lib/rails/engine.rb:514:incall' railties (4.1.1) lib/rails/application.rb:144:in call' rack (1.5.2) lib/rack/lock.rb:17:incall' rack (1.5.2) lib/rack/content_length.rb:14:in call' rack (1.5.2) lib/rack/handler/webrick.rb:60:inservice'

christhekeele commented 9 years ago

The error undefined method 'can_registrant_info?' for nil:NilClass suggests Authority can't find an actual user object to use in your controller. By default, it calls the current_user method in your controller, and then calls can_? methods on that.

Whatever your current_user implementation is, it's returning nil, which in turn is causing some grief during the authorization step.

If you have some other than method than current_user to get a user object, you can change what method Authority uses:

Authority.configure do |config|
  config.user_method = :my_controller_current_user_method
end

If current_user is returning nil because there isn't one–nobody's logged in–you have a few options. I recommend using the null object pattern in your current_user method rather than returning a raw nil. Depending on your application, something like this may work:

class NilUser
  def method_missing?(method_name, *args)
    nil
  end
end

Any method you send to an instance of this class will return falsey, including Authority methods. If current_user returns one of these instead for unauthenticated sessions, all authorization will fail for non-logged-in-users.

Another option is to avoid authorization entirely for all unauthenticated sessions by setting up a controller filter to redirect to a login page in all controllers that only logged in users ought to be able to see.

nathanl commented 9 years ago

@christhekeele just dropping by - :clap: :smile: