Forum: Ruby on Rails config.cache_classes breaks reflect_on_assocation ?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
10da297eedcca67860268ec3490f6f06?d=identicon&s=25 dino d. (Guest)
on 2009-02-19 21:51
(Received via mailing list)
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
81b61875e41eaa58887543635d556fca?d=identicon&s=25 Frederick Cheung (Guest)
on 2009-02-20 00:03
(Received via mailing list)
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
10da297eedcca67860268ec3490f6f06?d=identicon&s=25 dino d. (Guest)
on 2009-02-20 01:10
(Received via mailing list)
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 Cheung <frederick.che...@gmail.com>
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2009-02-20 02:32
(Received via mailing list)
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
81b61875e41eaa58887543635d556fca?d=identicon&s=25 Frederick Cheung (Guest)
on 2009-02-20 10:39
(Received via mailing list)
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
This topic is locked and can not be replied to.