# Caching objects

**URL:** <https://www.ruby-forum.com/t/caching-objects/96372>\
**Category:** Rails\
**Created:** [June 28, 2006, 1:28pm UTC](https://www.ruby-forum.com/t/caching-objects/96372 "2006-06-28T13:28:08Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 1:28pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/1 "2006-06-28T13:28:08Z")

</div>

Hi,

i just wanted to say my sorries in advance (sorrie/sorry/sorri)…i have  
just started learning about the subject of caching, but unfortunately  
haven’t effictively managed to implement what i had learned.  
obviously it’s possible to cache a whole page, or action with the  
caches\_page :x or caches\_action :y methods, but for some reason it  
hasn’t really worked with what i had been doing. (i was trying to cache  
Time.now to no avail)  
either way, the issue at hand (not Time.now) is trying to cache an  
object that i will usually pull out of the database once per  
session…say i have a table database.groups and i want to get all of  
the records out of the table, and keep them in my application, without  
pulling them out every other action (unless i specify otherwise)…

i was hoping there was something as simple as

MyController  
#here  
caches\_action :get\_groups

def index  
get\_groups  
end…

def another\_action  
get\_groups  
end  
…  
…  
private

#and here  
def get\_groups  
@groups = Group.find(:all)  
end

but i can’t get it to work! …i’m in production mode, with the  
ActionController::Base.perform\_caching = true  
and it still isn’t working! …any ideas to what i am doing wrong? oh,  
and also how do i ‘abort’ the caching for ‘get\_groups’ and overide that  
in order to look for the groups in a new db-query? (something like  
expire\_get\_groups)

much thanks in advance,  
s

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 3:56pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/2 "2006-06-28T15:56:14Z")

</div>

Wrong kind of caching 🙂 Action, page, and fragment caching are for the  
views. There isn’t any built-in support for doing database result  
caching.  
Building your own isn’t that hard, but first decide if it’s really  
necessary.

If you use page caching correctly, you can dramatically reduce your  
backend  
overhead because Rails never gets invoked. Rails makes static pages from  
your dynamic content and places those in your public folder. Subsequent  
hits  
are served from the static pages and Rails doesn’t even notice. (The web  
server is usually configured to only invoke Rails if the request is a  
404  
Page Not Found.)

If you use fragment caching, you can reduce a lot of database hits for  
things like dropdown boxes, etc.

I know that there are a couple of folks out there experimenting with  
database result caching. I am not familiar with it because I’ve been  
content  
with page and action caching.

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 5:16pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/3 "2006-06-28T17:16:52Z")

</div>

Brian H. wrote:

> Building your own isn’t that hard, but first decide if it’s really  
> necessary.

…i was kind of hoping to release the tension off of the db hits seeing  
that the ‘groups’ table will hardly be used, and so it would be  
unneccerary to look for all of the groups all the time (unless the admin  
would enter a new group which would happen rarely, and then i would  
envoke something simillar to expire\_\_…)  
so where would i start if i wanted to build my own method for this?  
where do i store it?

> If you use fragment caching, you can reduce a lot of database hits for  
> things like dropdown boxes, etc.

and if the fragment caching doesn’t involve db queries, how would i save  
the time? …i happen to be fairly new to this subject, so thanks for  
the patience and time(and at this time i could possibly throw in a  
general thanks for the reply)

s

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 5:44pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/4 "2006-06-28T17:44:50Z")

</div>

Fragment caching works well for things like select boxes… say for  
example  
you have ‘locations’ in your database. When you create a new inventory  
item,  
you might specify the location by picking it from a dropdown box.

You can build that select box of ‘locations’ using fragment caching. The  
DB  
gets hit once, the list is built, and then the fragment is used next  
time  
instead of the db. You need to expire the fragment when you add,  
modify,  
or delete a location. You do that manually, either directly or by using  
a  
sweeper. (See Agile Web D. for a good example of sweepers.)

As for how to cache your own results, first be sure you’re not doing any  
premature optimizing. Databases are meant to handle queries. Depending  
on  
how often the table is used, you can do tuning on the db side too, such  
as  
applying proper indexes.

I would write the app first and see how it performs under your expected  
load. If it performs poorly, then come back and ask for some specific  
options.

If you absolutely feel that you _have_ to do this functionality right  
now,  
I think that the BackgroundDRB plugin might help you (  
[http://backgroundrb.rubyforge.org/](http://backgroundrb.rubyforge.org/)).

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 5:48pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/5 "2006-06-28T17:48:16Z")

</div>

On Jun 28, 2006, at 10:16 AM, newbie wrote:

> would enter a new group which would happen rarely, and then i would  
> envoke something simillar to expire\_\_…)  
> so where would i start if i wanted to build my own method for this?  
> where do i store it?

This is generally done with a class variable. To use your earlier  
example, write code that looks similar to this:

def get\_groups  
@@groups ||= Group.find(:all)  
end

If @@groups isn’t set yet it will execute the Group.find call. If  
@@groups is set, it just returns itself. If the code looks strange,  
it is functionally equivalent to:

def get\_groups  
if @@groups.nil?  
@@groups = Group.find(:all)  
end  
return @@groups  
end

> > If you use fragment caching, you can reduce a lot of database hits  
> > for  
> > things like dropdown boxes, etc.
> 
> and if the fragment caching doesn’t involve db queries, how would i  
> save  
> the time?

I haven’t really experimented with fragment caching yet, so I’ll let  
someone else answer this one…

cr

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 7:51pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/6 "2006-06-28T19:51:29Z")

</div>

> > so where would i start if i wanted to build my own method for this?  
> > set, it just returns itself. If the code looks strange, it is functionally  
> > equivalent to:

Just keep in mind that this is _per_ rails process… so if you’re not  
careful about updating this when the database changes, you could have an  
instance where from “request to request” you would see different output  
for @@groups depending on what rails process your request was processed  
by.

-p

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 30, 2006, 1:34pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/7 "2006-06-30T13:34:48Z")

</div>

> Lastly, use “expire\_fragment(url\_params\_for\_fragment)” after any  
> controller action that changes the groups table. This way you always  
> have the speed of caching, but as soon as anything changes you wipe the  
> cache and let the next request generate the up to date content.

Thanks! …u’v been really helpful.  
last and may be least question; where do i put the expire\_fragment? in a  
helper? appcontoller?

---

<div class="post-metadata">

**Author:** ![newbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/dc4da7/32.png) [@newbie](https://www.ruby-forum.com/u/newbie)\
**Post date:** [June 28, 2006, 8:34pm UTC](https://www.ruby-forum.com/t/caching-objects/96372/8 "2006-06-28T20:34:56Z")

</div>

newbie wrote:

> i was hoping there was something as simple as
> 
> MyController  
> #here  
> caches\_action :get\_groups
> 
> def index  
> get\_groups  
> end…
> 
> def another\_action  
> get\_groups  
> end  
> …  
> …  
> private
> 
> #and here  
> def get\_groups  
> @groups = Group.find(:all)  
> end

Get rid of caches\_action, since that won’t do what you want. Try  
something more like:

#view  
\<% cache do %\>  
\<%= #bunch of complicated stuff to build groups page %\>  
\<% end %\>

#controller  
def get\_groups  
unless read\_fragment(params) #uses the url\_for helper to read the  
#cached fragment for this page.  
@groups = Group.find(:all)  
end  
end

So the action gets called the first time, read\_fragment does not find  
any cached fragment, so it sets @groups to the DB result.

Then, the view kicks in and the cache method doesn’t find the fragment,  
so it executed the code, and caches the result using the params of  
whatever page it’s on.

The next time the action gets called, read\_fragment finds the cached  
framgent, and skips the db call, and skips assigning the @groups  
variable. This is fine because as long as all the view data that uses  
the @groups variable is cached, the object will never be used.

Lastly, use “expire\_fragment(url\_params\_for\_fragment)” after any  
controller action that changes the groups table. This way you always  
have the speed of caching, but as soon as anything changes you wipe the  
cache and let the next request generate the up to date content.

Summary: Use “cache do” or “cache(some\_url\_params) do” in your view, and  
check to see if you can read that fragment from your controller before  
you do any DB calls. Then after any change that would alter what was  
cached use expire\_fragment to clear it.
