This project is archived and is in readonly mode.
Default scope and class reloading
Reported by Jose | August 30th, 2010 @ 01:59 PM | in 3.0.2
This crashes in Rails 3.0.0 (rc, rc1 and final). Clone this source to get a clean project that reproduces the bug: http://github.com/josei/default_scope_bug
Bascially, the project considers the following models:
class Conversation < ActiveRecord::Base
has_many :readings
has_many :users, :through => :readings
default_scope order('conversations.updated_at desc')
end
class Reading < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class User < ActiveRecord::Base
has_many :readings
has_many :conversations, :through => :readings
end
Perform these steps to reproduce the bug:
$ rake db:migrate
$ rails c
irb(main):001:0> User.create :name=>'Joe'
=> #<User id: 1, name: "Joe", created_at: "2010-08-30 12:25:41", updated_at: "2010-08-30 12:25:41">
irb(main):002:0> User.first.conversations.create :title=>'New conversation'
=> #<Conversation id: 1, title: "New conversation", created_at: "2010-08-30 12:25:55", updated_at: "2010-08-30 12:25:55">
irb(main):003:0> User.first.conversations.find(Conversation.first.id).users.first.is_a?(User)
=> true
irb(main):004:0> reload!
Reloading...
=> true
irb(main):005:0> User.first.conversations.find(Conversation.first.id).users.first.is_a?(User)
=> false
You can also check object_ids for class before reloading and after; it looks like there's a problem in class versioning. The line that causes the problem is default_scope at conversation.rb. You can try commenting out that line and repeating the last steps to check it now works:
$ rails c
irb(main):001:0> User.first.conversations.find(Conversation.first.id).users.first.is_a?(User)
=> true
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> User.first.conversations.find(Conversation.first.id).users.first.is_a?(User)
=> true
This is not a problem with class caching disabled, but is annoying in development mode. It seems that default_scope breaks class reloading and something related with @reflection in association_proxy.rb.
Comments and changes to this ticket
-
Andrew White September 1st, 2010 @ 12:23 PM
- Milestone cleared.
- State changed from new to open
- Assigned user set to Andrew White
- Importance changed from to High
Tricky one to track down this. It turns out that AR stores the default scope in a Thread.current variable. This keeps a copy of the class the first time it is loaded and when it's unloaded after each request it becomes stale.
A quick fix is to use the deprecated hash syntax for order:
default_scope :order => 'conversations.updated_at desc'
-
Jose September 1st, 2010 @ 12:46 PM
The quick fix doesn't change the behaviour, at least in my case (Rails 3.0.0 + Ruby 1.8.7).
-
Andrew White September 1st, 2010 @ 01:08 PM
Yes, you're right - sorry I thought I'd checked it worked.
Add this block to config/environment/development.rb and it should work even with the new syntax:
config.to_prepare do Thread.current.keys.each{ |k| Thread.current[k] = nil if k.to_s =~ /_scoped_methods$/ } end
Basically, it clears out all the cached default scope on each request for all models. This only matters in development so keep it inside development.rb until 3.0.1 gets released.
-
Andrew White September 1st, 2010 @ 03:18 PM
Patch for master which adds a callback to ActiveSupport::Dependencies.remove_unloadable_constants! in one commit and then uses that feature to reset the default scope when the class is unloaded in a second commit.
-
Andrew White September 1st, 2010 @ 03:22 PM
- Assigned user changed from Andrew White to Xavier Noria
-
Repository September 1st, 2010 @ 09:58 PM
- State changed from open to resolved
(from [aefa11be11a0a6b0c98b776c9e6422b2e0e4b13d]) Reset default scope in Thread.current when class is unloaded [#5497 state:resolved]
Signed-off-by: Xavier Noria fxn@hashref.com
http://github.com/rails/rails/commit/aefa11be11a0a6b0c98b776c9e6422... -
Repository September 1st, 2010 @ 09:58 PM
(from [4e67bf26aa11a59e4f513359208fe3314c5a1ba5]) Reset default scope in Thread.current when class is unloaded [#5497 state:resolved]
Signed-off-by: Xavier Noria fxn@hashref.com
http://github.com/rails/rails/commit/4e67bf26aa11a59e4f513359208fe3...
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Attachments
Referenced by
- 5347 default_scope order(...), PostgreSQL, and has_and_belongs_to_many cause AssociationTypeMismatch exception @Paul can you try suggestion mentioned here https://rail...
- 5497 Default scope and class reloading (from [aefa11be11a0a6b0c98b776c9e6422b2e0e4b13d]) Reset d...
- 5497 Default scope and class reloading (from [4e67bf26aa11a59e4f513359208fe3314c5a1ba5]) Reset d...
- 3809 default scope not changing when class is unloaded and reloaded Yes, it was fixed by the commits on #5497 - though lookin...
- 5853 AssociationTypeMismatch, different versions of a class loaded Are you using default_scope anywhere? After much digging,...