Wrong class being returned in association

I'm using Rails 3.0.0rc and have the following models:

class User has_many :readings has_many :conversations, :through=>:readings end

class Reading belongs_to :user belongs_to :conversation end

class Conversation has_many :readings has_many :users, :through=>:readings end

and this controller code:

class ConversationsController def show @user = User.find(params[:user_id]) @conversation = @user.conversations.find(params[:id]) debugger end end

After requesting conversations#show, go to debug console and:

User.class.object_id => 116350 @conversation.users.first.class.object_id => 33660870 @conversation.users.first.instance_of? User => true # Right

Then leave debugging and request the page again: User.class.object_id => 116350 @conversation.users.first.class.object_id => 36497930 @conversation.users.first.instance_of? User => true # Right

And then, request the page again: User.class.object_id => 116350 @conversation.users.first.class.object_id => 36497930 @conversation.users.first.class.to_s == User.to_s => true @conversation.users.first.instance_of? User => false # Wrong!

This last evaluation is wrong, and breaks equality checks and expressions such as @conversation.users.include?(some_user)

If I enable class caching, the problem disappears (but that's not ideal for development). Maybe I'm doing something that breaks @reflection in association_proxy.rb? Any ideas?

Sounds like you might be breaking class reloading somehow. It's possible to do this in such a way that you have both new and old versions of a class, which are then not equal. In the past I've found explicit require statements (rather than require_dependency) could do that (because require doesn't (or at least didn't) invoke the dependency stuff at all). Models in plugins can also do this, because typically plugins aren't reloaded, so if you have an association between a plugin model (that doesn't get reloaded) and an application model (which does) then weird stuff happens.

Fred

That makes a lot of sense. I'm using authlogic and acts_as_follower in the user model. Turning them off to check which one is producing the issue is hard, but I'll have to try. Is there a way to force plugin classes to reload? Or, what could be the 'best practice' that is not being followed in these plugins?

That makes a lot of sense. I'm using authlogic and acts_as_follower in the user model. Turning them off to check which one is producing the issue is hard, but I'll have to try. Is there a way to force plugin classes to reload? Or, what could be the 'best practice' that is not being followed in these plugins?

In 2.3 you can remove stuff from ActiveSupport::load_once_paths - remove the path to the plugin's lib dir and you should be fine (I think by the time initializers run plugins are all setup so that's probably a good a place as any to do that)

Fred

After some research it seems that's not the cause of the problem. I created a blank project, removed all plugins and the error persisted:

User.last.conversations.find(Conversation.last.id).users.last.instance_of?(User)

=> true

reload!

Reloading... => true

User.last.conversations.find(Conversation.last.id).users.last.instance_of?(User)

=> false

I removed this line I had in the Conversation model:

  default_scope :order => 'updated_at desc'

Now the models are exactly as shown in my first post, and now there's no class bug. Of course, I have been testing with only one user, one conversation and one reading (otherwise the order in the default scope would make a big change in the query).