Config.cache_classes breaks reflect_on_assocation?


#1

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


#2

On 19 Feb 2009, at 20:50, dino d. wrote:

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


#3

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

On Feb 19, 6:02 pm, Frederick C. removed_email_address@domain.invalid


#4

dino d. wrote:

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 }


Rails Wheels - Find Plugins, List & Sell Plugins -
http://railswheels.com


#5

On 20 Feb 2009, at 00:09, dino d. wrote:

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