config.cache_classes breaks reflect_on_assocation ?

Hi - I have a model with a user-specific has_one relationship, meaning, my model, Story, has one Vote, but only on a per-user basis. So, I addressed this issue by adding a has_one relationship:

has_one :current_user_vote, :class_name => 'Vote', :conditions => "user_id = #{Story.current_user ? Story.current_user.id : -1}"

And, I added a cattr_accessor, current_user (so now the model Story has a current user).

And, when the user logs in (or gets logged in by cookie), the method set_current_user gets called automatically, which looks like this:

def self.set_current_user user     if user       holder = user.id     else       holder = -1     end     reflect_on_association(:current_user_vote).options[:conditions] =       "votes.user_id = #{holder}"     self.current_user = user   end

This works fine, unless I enable config.cache_classes, then, the first user who accesses the site after the server is restarted gets his id set to current_user, and everyone else afterward gets the first guy's user_id set in the association.

So, is there a way to disable only model caching, and cache everything else? Or, is this a bug?

Thanks for any help, Dino

This works fine, unless I enable config.cache_classes, then, the first user who accesses the site after the server is restarted gets his id set to current_user, and everyone else afterward gets the first guy's user_id set in the association.

So, is there a way to disable only model caching, and cache everything else? Or, is this a bug?

This isn't a bug - you're relying on something you should be relying
on. The reflection builds the sql statement it needs to load the
association but caches that sql thereafter. I don't think there's a way round this without changing the way you're
doing things.

Fred

thanks fred (i knew you would be the guy to answer this). so, it sounds like you cannot 'refresh' a cached model, and once it's cached, you can't modify it's cattr (is this right?) . hmm... do you have a suggestion for a workaround? I basically have users, stories, and votes. users vote on stories. so, i want load all stories and their associated votes for a particular user. this was the only way i could think of to make a 3 way join.

in the main view of my app, i need to show a batch of stories, with all the votes for each story, and the current user's vote for that story, and i want to do it with a single query. adding a current user to the model and the reflect_on does this, and i can't think of any other way.

does class caching dramatically improve performance?

without class caching, am i correct to assume that each session has it's own model object?

thanks again, dino

dino d. wrote:

def self.set_current_user user     if user       holder = user.id     else       holder = -1     end     reflect_on_association(:current_user_vote).options[:conditions] =       "votes.user_id = #{holder}"     self.current_user = user   end

This works fine, unless I enable config.cache_classes, then, the first user who accesses the site after the server is restarted gets his id set to current_user, and everyone else afterward gets the first guy's user_id set in the association.

Yes, this trick stopped working in 2.2 because the reflection now caches its conditions SQL.

One workaround is

reflection = reflect_on_association(:current_user_vote) reflection.options[:conditions] = "votes.user_id = #{holder}" reflection.instance_eval { @sanitized_conditions = nil }

thanks fred (i knew you would be the guy to answer this). so, it sounds like you cannot 'refresh' a cached model, and once it's cached, you can't modify it's cattr (is this right?) . hmm... do you have a suggestion for a workaround? I basically have users, stories, and votes. users vote on stories. so, i want load all stories and their associated votes for a particular user. this was the only way i could think of to make a 3 way join.

in the main view of my app, i need to show a batch of stories, with all the votes for each story, and the current user's vote for that story, and i want to do it with a single query.

adding a current user to the model and the reflect_on does this, and i can't think of any other way.

It's not nice but you could have an interpolated condition ie

has_one :blah, :conditions => 'user_id = #{Story.current_user ?
Story.current_user.id : -1}'

(note the single quotes there).

I think you'd be better off with something that didn't involve a class
level variable like this.

something not far removed from

Story.find :all, :include => :votes, :conditions => ["votes.id IS NULL
OR votes.user_id = ?", foo]

would do the trick (this is a bit messy in that story.votes will now
return only votes matching the user)

does class caching dramatically improve performance?

Yes. It's pretty much the biggest thing (along with caching in the
sense of fragment caching etc.) that separates development from
production performance wise.

Fred