# Action Association Caching

**URL:** <https://www.ruby-forum.com/t/action-association-caching/144862>\
**Category:** Rails\
**Created:** [August 3, 2008, 2:46pm UTC](https://www.ruby-forum.com/t/action-association-caching/144862 "2008-08-03T14:46:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![stefan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@stefan](https://www.ruby-forum.com/u/stefan)\
**Post date:** [August 3, 2008, 2:46pm UTC](https://www.ruby-forum.com/t/action-association-caching/144862/1 "2008-08-03T14:46:08Z")

</div>

Hey again guys,

I did come up with a problem few weeks ago and I still don’t have an  
elegant solution for it. I’d like to hear your opinions on how to deal  
with it, since it’s rather basic and could be quite common.

Imagine a view showing peoples clothing.  
Stefan’s hat: stefan.cloths.find\_by\_location “head”  
Stefan’s shirt: stefan.cloths.find\_by\_location “shirt”  
Stefan’s jeans: stefan.cloths.find\_by\_location “jeans”  
Stefan’s left\_glove: stefan.cloths.find\_by\_location “left\_glove”  
Stefan’s right\_glove: stefan.cloths.find\_by\_location “right\_glove”  
etc…

quite a few queries. bad performance. the thing is though, before  
reaching the view the association has been already initialized. so, the  
rows already exist in the action, and they are retrieved again  
one-by-one in the view.

to avoid retrieving them again, i build a hash in the action this way:  
for cloth in cloths; @cached\_clothes[cloth.location] = cloth; end  
and in the view:  
Stefan’s hat: @cached\_clothes[“head”]

It “works”. But does not seem elegant. an other approach i tried:  
Stefan’s hat: stefan.clothes.select{|c| c.location == “head”}.first  
Doesnt seem to be the correct “rails way” either.

Is there a “rails way” for doing this?

Thank you 😉  
Stefan

---

<div class="post-metadata">

**Author:** ![stefan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@stefan](https://www.ruby-forum.com/u/stefan)\
**Post date:** [August 3, 2008, 10:41pm UTC](https://www.ruby-forum.com/t/action-association-caching/144862/2 "2008-08-03T22:41:17Z")

</div>

Anyone an opinion on one of the two ways i’m doing it? Can someone think  
of a better way?

---

<div class="post-metadata">

**Author:** ![stefan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@stefan](https://www.ruby-forum.com/u/stefan)\
**Post date:** [August 4, 2008, 1:16am UTC](https://www.ruby-forum.com/t/action-association-caching/144862/3 "2008-08-04T01:16:51Z")

</div>

On 3 Aug 2008, at 13:46, Stefan B. wrote:

> to avoid retrieving them again, i build a hash in the action this way:  
> for cloth in cloths; @cached\_clothes[cloth.location] = cloth; end  
> and in the view:  
> Stefan’s hat: @cached\_clothes[“head”]

You can make this slightly neater by saying @cached\_clothes =  
stefan.clothes.index\_by {|c| c.location}

> It “works”. But does not seem elegant. an other approach i tried:  
> Stefan’s hat: stefan.clothes.select{|c| c.location == “head”}.first  
> Doesnt seem to be the correct “rails way” either.

Seems reasonable enough. If there were a lot of clothes and clothe  
locations the hash approach might be more efficient, but until then it  
could be over the top.  
If you wanted the syntax to be cleaner I suppose you could fiddle  
around with an association extension, eg

has\_many :clothes do  
def select\_by attribute, value  
detect {|c| c.send(attribute) == value}  
end  
end

and then you can do stefan.clothes.select\_by :location, ‘head’  
You could even go the whole hod and leverage method\_missing to handle  
things like clothes.select\_by\_location ‘x’

If you’re only ever doing this by location, you can make things a  
little shorter

has\_many :clothes do  
def located\_on place  
detect {|c| c.location == place}  
end  
end

and then you can write stefan.clothes.located\_on ‘head’

or apply association extensions to the first technique:

has\_many :clothes do  
def located\_on place  
@cache ||= index\_by {|c| c.location}  
@cache[place]  
end  
end  
(this may or may not be a concern, but in this case you do need to  
worry about @cache getting stale, eg as is reloading the association  
won’t clear it)

Fred

---

<div class="post-metadata">

**Author:** ![stefan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@stefan](https://www.ruby-forum.com/u/stefan)\
**Post date:** [August 4, 2008, 2:47am UTC](https://www.ruby-forum.com/t/action-association-caching/144862/4 "2008-08-04T02:47:22Z")

</div>

Thanks again fred.

This association extension thing seems like the piece of the puzzle I  
was missing.
