undefined method 'locked' for #<Class:...> #7421

Closed
vongruenigen opened this Issue Aug 22, 2012 · 20 comments

Projects

None yet

8 participants

We use the ActiveRecord::FinderMethods#exists? method on one of our models in an initializer which registers a Warden callback.

Warden::Manager.after_fetch do |user, auth, opts|
  if MyModel.exists?(:attribute => true)
    # ...
  end
end

The problem is that it randomly fails with the following exception: undefined method 'locked' for #<Class:0x007fdab3025298>. After the exception occured the first time, no other action can be accessed anymore because the same exception is thrown every time the warden callback is run.

I tried to figure out where the problem occurs and I thinks its here. But that's a bit strange because it checks if the arel object in this case responds to :locked before calling it.

Here's the full trace of the exception:

activerecord (3.2.8) lib/active_record/dynamic_matchers.rb:50:in `method_missing'
activerecord (3.2.8) lib/active_record/relation/delegation.rb:14:in `block in locked'
activerecord (3.2.8) lib/active_record/relation.rb:241:in `block in scoping'
activerecord (3.2.8) lib/active_record/scoping.rb:98:in `with_scope'
activerecord (3.2.8) lib/active_record/relation.rb:241:in `scoping'
activerecord (3.2.8) lib/active_record/relation/delegation.rb:14:in `locked'
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/query_cache.rb:83:in `locked?'
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/query_cache.rb:59:in `select_all'
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/database_statements.rb:24:in `select_one'
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/database_statements.rb:30:in `select_value'
activerecord (3.2.8) lib/active_record/relation/finder_methods.rb:202:in `exists?'
activerecord (3.2.8) lib/active_record/querying.rb:5:in `exists?'
config/initializers/warden_callbacks.rb:21:in `block in <top (required)>'
warden (1.2.1) lib/warden/hooks.rb:14:in `call'
warden (1.2.1) lib/warden/hooks.rb:14:in `block in _run_callbacks'
warden (1.2.1) lib/warden/hooks.rb:9:in `each'
warden (1.2.1) lib/warden/hooks.rb:9:in `_run_callbacks'
warden (1.2.1) lib/warden/manager.rb:53:in `_run_callbacks'
warden (1.2.1) lib/warden/proxy.rb:179:in `set_user'
warden (1.2.1) lib/warden/proxy.rb:217:in `user'
warden (1.2.1) lib/warden/proxy.rb:318:in `_perform_authentication'
warden (1.2.1) lib/warden/proxy.rb:127:in `authenticate!'
devise (2.1.2) lib/devise/controllers/helpers.rb:48:in `authenticate_user!'
activesupport (3.2.8) lib/active_support/callbacks.rb:441:in `block in _run__1781825415374613391__process_action__672509108191995934__callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:215:in `block in _conditional_callback_around_5355'
activesupport (3.2.8) lib/active_support/callbacks.rb:326:in `around'
activesupport (3.2.8) lib/active_support/callbacks.rb:310:in `_callback_around_13'
activesupport (3.2.8) lib/active_support/callbacks.rb:214:in `_conditional_callback_around_5355'
activesupport (3.2.8) lib/active_support/callbacks.rb:414:in `_run__1781825415374613391__process_action__672509108191995934__callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `__run_callback'
activesupport (3.2.8) lib/active_support/callbacks.rb:385:in `_run_process_action_callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (3.2.8) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (3.2.8) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (3.2.8) lib/action_controller/metal/instrumentation.rb:30:in `block in process_action'
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `block in instrument'
activesupport (3.2.8) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `instrument'
actionpack (3.2.8) lib/action_controller/metal/instrumentation.rb:29:in `process_action'
actionpack (3.2.8) lib/action_controller/metal/params_wrapper.rb:207:in `process_action'
activerecord (3.2.8) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (3.2.8) lib/abstract_controller/base.rb:121:in `process'
actionpack (3.2.8) lib/abstract_controller/rendering.rb:45:in `process'
actionpack (3.2.8) lib/action_controller/metal.rb:203:in `dispatch'
actionpack (3.2.8) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch'
actionpack (3.2.8) lib/action_controller/metal.rb:246:in `block in action'
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:73:in `call'
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:73:in `dispatch'
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:36:in `call'
journey (1.0.4) lib/journey/router.rb:68:in `block in call'
journey (1.0.4) lib/journey/router.rb:56:in `each'
journey (1.0.4) lib/journey/router.rb:56:in `call'
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:600:in `call'
warden (1.2.1) lib/warden/manager.rb:35:in `block in call'
warden (1.2.1) lib/warden/manager.rb:34:in `catch'
warden (1.2.1) lib/warden/manager.rb:34:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
rack (1.4.1) lib/rack/etag.rb:23:in `call'
rack (1.4.1) lib/rack/conditionalget.rb:25:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/head.rb:14:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/params_parser.rb:21:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/flash.rb:242:in `call'
rack (1.4.1) lib/rack/session/abstract/id.rb:205:in `context'
rack (1.4.1) lib/rack/session/abstract/id.rb:200:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/cookies.rb:339:in `call'
activerecord (3.2.8) lib/active_record/query_cache.rb:64:in `call'
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/connection_pool.rb:473:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `_run__4125333889746358287__call__3170945389804826198__callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `__run_callback'
activesupport (3.2.8) lib/active_support/callbacks.rb:385:in `_run_call_callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (3.2.8) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/reloader.rb:65:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/remote_ip.rb:31:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
railties (3.2.8) lib/rails/rack/logger.rb:26:in `call_app'
railties (3.2.8) lib/rails/rack/logger.rb:14:in `block in call'
activesupport (3.2.8) lib/active_support/tagged_logging.rb:25:in `tagged'
railties (3.2.8) lib/rails/rack/logger.rb:14:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/request_id.rb:22:in `call'
rack (1.4.1) lib/rack/methodoverride.rb:21:in `call'
rack (1.4.1) lib/rack/runtime.rb:17:in `call'
activesupport (3.2.8) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.4.1) lib/rack/lock.rb:15:in `call'
actionpack (3.2.8) lib/action_dispatch/middleware/static.rb:62:in `call'
railties (3.2.8) lib/rails/engine.rb:479:in `call'
railties (3.2.8) lib/rails/application.rb:223:in `call'
rack (1.4.1) lib/rack/content_length.rb:14:in `call'
railties (3.2.8) lib/rails/rack/log_tailer.rb:17:in `call'
rack (1.4.1) lib/rack/handler/webrick.rb:59:in `service'
/Users/dvg/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpserver.rb:138:in `service'
/Users/dvg/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpserver.rb:94:in `run'
/Users/dvg/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'

After restarting the application the problem disappears.

The problem occurs in both development and production environments. We're using Rails 3.2.8 with Ruby 1.9.3.

Member

Hmm, is this related to #6985?

Owner

Could you provide an example application reproducing this issue?

@steveklabnik Yes, looks like it's somehow related to that.
@rafaelfranca I will try to create one where I can reproduce the problem asap.

@rafaelfranca I created an app to reproduce the issue, but that wasn't as easy as I thought. I couldn't reproduce it until now. Anyway, you can find the app here.

The gems are exactly the same as in our real application and all parts which I think could have a side effect (e.g. :locked scope on user model) are also there in a similar manner. In our application the exception gets thrown in the Warden callback which you can find in the warden_hooks.rb file when executing Item.exists?(...). It's executed on every request when Warden has fetched the currently logged in user.

I will go on trying to reproduce the issue as far as I can. Maybe your eyes see something in meantime which could help to solve the issue.

Thanks for your help!

Owner

Hmm, I could not reproduce using you application.

It'd help if we could know what #<Class:0x007fdab3025298> means.

I also don't know what kind of class that is, but I found a temporary solution in the meantime: We've had a locked scope on our model, after renaming it, the problem seems to disappear.

Member

Ahh, name clashes. That's the worst. Since we can't reproduce with the clean one, should we close?

Contributor
al2o3cr commented Oct 22, 2012

Just recently helped some colleagues who were hitting the same thing - looked to be a collision between the locked scope and a method defined by ARel on Relation (to deal with pessimistic locking).

@steveklabnik Hmm, I would let it open, so maybe somebody finds time to investigate and fix the problem?
@al2o3cr Yes, but the strange thing is that it happens more or less randomly and after the problem occured the first time, my only solution was to restart your rails process..

Member

There isn't a problem. If you name something the same as an ActiveRecord feature, you're gonna have a bad time.

@steveklabnik It's something internal of arel, and I think it should at least be mentioned in the documentation for scopes, that this identifier cannot be used. Especially when it happens in a random manner.

Member

Sure. Well, this isn't a bug, so I'm closing. If @rafaelfranca disagrees, he can re-open. :) If you think the docs should be better, feel free to submit a pull request improving them. I'm always 👍 on improving docs.

Ok, maybe I got some time in the next few days to take a look at it. :)

Member

:)

Owner

👍 I have this in my icebox, but we can close this one.

Contributor

I disagree with this being closed. It's not that it fails, it's that it fails randomly and there is no mention in the documentation or change logs that 'locked' is now a special name.

When we upgraded our app with a 'locked' scope to 3.2, all the tests pass including extensive rspec and cucumber tests, the code still works the same way in dev mode and prod mode on my laptop, the code still works the same way on the console on the production servers, but randomly the web servers run something completely different.

This is not good code. If it's not even deterministic, let alone documented, it's not reasonable to change the behavior in this way.

@willbryant willbryant added a commit to willbryant/rails that referenced this issue May 28, 2013
@willbryant willbryant remove unnecessary arel delegation on relations, which meant that dep…
…ending on what code ran first, scopes named the same as any arel method may or may not get replaced by the arel method, which may or may not show up in tests. keep the #ast delegation as that is commonly used, write out two other calls to it, one of which was already involved in the guts of arel. fixes the old GH issue #7421.
7e46c20
Contributor

This turned out to be really easy to fix for 3.2 as there are very few calls that actually used the arel delegation. Patched my tree in:

7e46c20 remove unnecessary arel delegation on relations, which meant that depending on what code ran first, scopes named the same as any arel method may or may not get replaced by the arel method, which may or may not show up in tests. keep the #ast delegation as that is commonly used, write out two other calls to it, one of which was already involved in the guts of arel. fixes the old GH issue #7421.

Not worth trying to get this into 3.2 but since this problem is just going to get worse and worse as arel adds more methods, I'll try and apply it to master and then send a pull request. Could possibly help with the #6985 discussion too.

tlrdstd commented Aug 8, 2013

@willbryant Did this ever make it into a pull request? I'm seeing this same problem during an upgrade, and it's not practical for us to rename all of our scopes named "locked." I'd like to apply your patch to our codebase, but it'd be nice to know if we're going to have the same issue in 4.0.

amk-boCO commented Sep 4, 2013

Super helpful thread. In full agreement with @willbryant re: missing documentation and non-deterministic execution. 👍

@willbryant willbryant added a commit to powershop/rails that referenced this issue Sep 4, 2014
@willbryant willbryant remove unnecessary arel delegation on relations, which meant that dep…
…ending on what code ran first, scopes named the same as any arel method may or may not get replaced by the arel method, which may or may not show up in tests. keep the #ast delegation as that is commonly used, write out two other calls to it, one of which was already involved in the guts of arel. fixes the old GH issue #7421.
41e352d
besi commented Jan 31, 2015

I get the same error in a different situation.
See http://stackoverflow.com/q/28254563/nomethoderror-undefined-method-locked

Any ideas what I am doing wrong?

@willbryant willbryant added a commit to powershop/rails that referenced this issue Aug 3, 2015
@willbryant willbryant + Van Veñegas remove unnecessary arel delegation on relations, which meant that dep…
…ending on what code ran first, scopes named the same as any arel method may or may not get replaced by the arel method, which may or may not show up in tests. keep the #ast delegation as that is commonly used, write out two other calls to it, one of which was already involved in the guts of arel. fixes the old GH issue #7421.
41b51f7
@cyoungberg cyoungberg added a commit to Acornsgrow/aasm that referenced this issue Nov 18, 2015
@cyoungberg cyoungberg Skip creation of individual scopes
There is some arel issues if you declare a scope with the name
`locked`, so we need a way to skip the creation the of individual
scopes.

See: rails/rails#7421 for more info
873d291
@cyoungberg cyoungberg added a commit to Acornsgrow/aasm that referenced this issue Nov 18, 2015
@cyoungberg cyoungberg Skip creation of individual scopes
There is some arel issues if you declare a scope with the name
`locked`, so we need a way to skip the creation the of individual
scopes.

See: rails/rails#7421 for more info
bec3097
@cyoungberg cyoungberg referenced this issue in Acornsgrow/aasm Nov 18, 2015
Open

Skip creation of individual scopes #1

@mkrfowler mkrfowler pushed a commit to powershop/rails that referenced this issue Jul 28, 2016
@willbryant willbryant + Van Veñegas remove unnecessary arel delegation on relations, which meant that dep…
…ending on what code ran first, scopes named the same as any arel method may or may not get replaced by the arel method, which may or may not show up in tests. keep the #ast delegation as that is commonly used, write out two other calls to it, one of which was already involved in the guts of arel. fixes the old GH issue #7421.
5daeb52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment