# Undesireable lazy loading

**URL:** <https://www.ruby-forum.com/t/undesireable-lazy-loading/60420>\
**Category:** Rails\
**Created:** [May 13, 2006, 12:01pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420 "2006-05-13T12:01:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Piotr\_Chmolowski](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8baadc/32.png) [@Piotr\_Chmolowski](https://www.ruby-forum.com/u/Piotr_Chmolowski)\
**Post date:** [May 13, 2006, 12:01pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420/1 "2006-05-13T12:01:08Z")

</div>

Hi,

My work with Rails has been fairly straightforward, until yesterday…  
I’ve encountered rather a peculiar problem that I’m not able to solve  
myself as a rails-newbie.

The model code looks like this:

class Link \< ActiveRecord::Base  
has\_one :user\_vote  
end

class UserVote \< ActiveRecord::Base  
belongs\_to :user  
belongs\_to :link  
end

I have a SQL query that is responsible for pulling out all links along  
with votes from a database:

links = Link.find\_by\_sql(  
[“SELECT \* FROM links LEFT JOIN user\_votes ON links.id =  
user\_votes.link\_id” +  
" AND user\_votes.user\_id = ?", session[:user\_id]]  
)

If a user hadn’t voted for a given link yet, an empty record is returned  
(NULL). The problem is that when trying to call that unexisting  
associated object (link.user\_vote) Rails attempts to retrieve it from  
the database. This can result in getting a vote that belongs to another  
user.

Is it possible to disable the lazy-loading feature for that particular  
association?

Is there any other way to perform the above-mentioned JOIN without using  
find\_by\_sql?

## thanks in advance,

Piotr Chmolowski

---

<div class="post-metadata">

**Author:** ![Piotr\_Chmolowski](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8baadc/32.png) [@Piotr\_Chmolowski](https://www.ruby-forum.com/u/Piotr_Chmolowski)\
**Post date:** [May 13, 2006, 1:49pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420/2 "2006-05-13T13:49:21Z")

</div>

> Is there any other way to perform the above-mentioned JOIN without using  
> find\_by\_sql?

In your user model:

class User \< ActiveRecord::Base  
has\_many :user\_votes  
end

Then you can say:

User.find(session[:user\_id]).user\_votes

Tom.

---

<div class="post-metadata">

**Author:** ![Piotr\_Chmolowski](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8baadc/32.png) [@Piotr\_Chmolowski](https://www.ruby-forum.com/u/Piotr_Chmolowski)\
**Post date:** [May 13, 2006, 2:52pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420/3 "2006-05-13T14:52:50Z")

</div>

Hi,

> class User \< ActiveRecord::Base  
> has\_many :user\_votes  
> end
> 
> Then you can say:
> 
> User.find(session[:user\_id]).user\_votes

This is not what I’m trying to achieve. I need a to pull out a list of  
links and check if the logged-in user has already voted for a given  
link. Using has\_many would require n + 1 queries for n links. That’s way  
too much. Besides, when specyfying the has\_many association I’d need to  
include session[:user\_id] in :conditions, which is AFAIK unfeasible, as  
the session isn’t available in model:

class Link  
has\_many :user\_votes, :conditions =\> [“user\_id = ?”,  
session[:user\_id]]  
end

---

<div class="post-metadata">

**Author:** ![Piotr\_Chmolowski](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8baadc/32.png) [@Piotr\_Chmolowski](https://www.ruby-forum.com/u/Piotr_Chmolowski)\
**Post date:** [May 13, 2006, 3:23pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420/4 "2006-05-13T15:23:35Z")

</div>

> This is not what I’m trying to achieve. I need a to pull out a list of  
> links and check if the logged-in user has already voted for a given  
> link. Using has\_many would require n + 1 queries for n links.

You can do User.find(session[:user\_id], :include =\>  
:user\_vote).user\_votes to retrieve all the user votes in one query.

> That’s way  
> too much. Besides, when specyfying the has\_many association I’d need to  
> include session[:user\_id] in :conditions, which is AFAIK unfeasible, as  
> the session isn’t available in model:
> 
> class Link  
> has\_many :user\_votes, :conditions =\> [“user\_id = ?”,  
> session[:user\_id]]  
> end

You wouldn’t need to do this. Since you’re looking for votes cast on  
links for a given user, just do @user.user\_votes. Any links not voted on  
won’t have vote objects, so there won’t be any nil anywhere.

This should probably do what you want:

User.find(session[:user\_id]).user\_votes.find(:all, :include =\> :link)

then just iterate through the list. Should only be 2 queries.

---

<div class="post-metadata">

**Author:** ![Piotr\_Chmolowski](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/8baadc/32.png) [@Piotr\_Chmolowski](https://www.ruby-forum.com/u/Piotr_Chmolowski)\
**Post date:** [May 13, 2006, 4:34pm UTC](https://www.ruby-forum.com/t/undesireable-lazy-loading/60420/5 "2006-05-13T16:34:24Z")

</div>

> This should probably do what you want:
> 
> User.find(session[:user\_id]).user\_votes.find(:all, :include =\> :link)
> 
> then just iterate through the list. Should only be 2 queries.

OK, I guess I haven’t explained it clearly enough. My site is pretty  
similar to [digg.com](http://digg.com) - I have a list of links, that everybody can vote  
on. Users can vote only after logging in. Only 1 vote is allowed for 1  
link. The code you suggested wouldn’t be suitable here, as it would give  
me only the links that the user had already voted on, and I want them  
all 🙂

Basically, the SQL I’ve posted in my first message does exactly what I  
want, but Rails is messing up the result trying to load the vote again,  
which can result in getting another user’s vote.

My link table looks like this:

id  
title  
url  
description

The votes table:

id  
link\_id  
user\_id  
voted\_at

The SELECT \* FROM links LEFT JOIN user\_votes ON links.id =  
user\_votes.link\_id AND user\_votes.user\_id = session[:user\_id]

lists all links. If the current user hadn’t voted for a given link yet,  
mysql returns an empty record. When iterating through that list of links  
I check if the user can vote for a given link:

\<% unless link.user\_vote %\>  
\<%= link\_to “vote!”, :action =\> “vote” %\>  
\<% end %\>

Rather that returning nil here, Rails performs the following (or  
similar) SQL query:

SELECT \* FROM user\_votes WHERE link\_id = X LIMIT 1

English is still my Achilles heel, so forgive me for my grammar and the  
way of explaining things in general 😉
