# Caching database data that doesn't change

**URL:** <https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318>\
**Category:** Rails\
**Created:** [February 16, 2008, 5:59pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318 "2008-02-16T17:59:51Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 16, 2008, 5:59pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/1 "2008-02-16T17:59:51Z")

</div>

what is the best way to cache database data that doesn’t change?  
I was caching it in a constant that I set in a file in  
config/initializers/ . More concretely, I have a file  
config/initializers/db\_cache\_constants.rb that contains the following  
line:

CATEGORIES = Category.find :all

But I have 2 problems:

- If I do a rake db:drop, then rake db:create doesn’t work because it  
tries to run that file, and it fails because there’s no database.

- when from a template I try to get the number of products of one of the  
cached categories (a category :has\_many products),

\<% for category in CATEGORIES %\>  
\<%= category.name %\> (\<%= category.products.size %\>)  
\<% end %\>

it works the first time, but when I reload the page, a NoMethodError  
occurs…  
undefined method ‘products’ for #\<Category id: 1, name: “category 1”\>

Why is this happening?

Both problems are solved if I move the definition of the constant to the  
beginning of the app/controllers/application.rb file, just before the  
definition of the ApplicationController class, but…

is there a better place to do this type of caching?

Thanks in advance.

xavi

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 12:32am UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/2 "2008-02-18T00:32:36Z")

</div>

Since the definition of a ‘class’ in Ruby is actually a method that  
runs in the context of that class, you can declare the constant on the  
class. It will already have inherited the :find method from  
ActiveRecord.

class Category  
CATEGORIES = self.find(:all)  
…  
end

Any time you need CATEGORIES after that you simply ‘prefix’ it through  
the class (Category::CATEGORIES).

AndyV

On Feb 16, 11:59 am, Xavi C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 11:25am UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/3 "2008-02-18T11:25:39Z")

</div>

Thanks for your answer, but…  
I tried defining the constant in the Category class like you said, but  
then for some reason caching doesn’t work: each time I reload the page  
that loops through the Category::CATEGORIES array I can see in the logs  
that the database is hit.

Category Load (0.000365) SELECT \* FROM `categories`  
Category Columns (0.002079) SHOW FIELDS FROM `categories`

The app is running in the development environment.

xavi

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 2:54pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/4 "2008-02-18T14:54:59Z")

</div>

have you tried running in production mode? in development mode all  
your models are reloaded with each request, so it will of course  
reload the categories. See what happens in production.

On Feb 18, 10:25 am, Xavi C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 4:27pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/5 "2008-02-18T16:27:54Z")

</div>

Thank you all for your answers.

I changed the config.cache\_classes option to true in the development  
environment (it’s set to false by default) and now the cache works, so  
you’re right that the cache didn’t work because of the default class  
reloading in development mode.

Fred, using a Category.all\_categories method, how would you store the  
cached data? in a class variable? in a constant?

Thanks again.

xavi

Frederick C. wrote:

> On 16 Feb 2008, at 16:59, Xavi C. wrote:
> 
> > But I have 2 problems:  
> > \<% end %\>
> > 
> > it works the first time, but when I reload the page, a NoMethodError  
> > occurs…  
> > undefined method ‘products’ for #\<Category id: 1, name: “category 1”\>
> > 
> > Why is this happening?
> 
> My hunch is that this is because of class reloading in development  
> mode: after the first request, rails will unload all of your models  
> (so that changes you make take effect immediately). It will basically  
> remove all the methods, constants etc… from for example the Category  
> model. Via your CATEGORIES constant you are still holding onto  
> instances of that old class, that no longer has any methods. You could  
> get round this if it was defined in your category.rb file
> 
> Personally I’d probably have a Category.all\_categories method which  
> would return cached data
> 
> Fred

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 3:45pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/6 "2008-02-18T15:45:38Z")

</div>

On 16 Feb 2008, at 16:59, Xavi C. wrote:

> But I have 2 problems:  
> \<% end %\>
> 
> it works the first time, but when I reload the page, a NoMethodError  
> occurs…  
> undefined method ‘products’ for #\<Category id: 1, name: “category 1”\>
> 
> Why is this happening?

My hunch is that this is because of class reloading in development  
mode: after the first request, rails will unload all of your models  
(so that changes you make take effect immediately). It will basically  
remove all the methods, constants etc… from for example the Category  
model. Via your CATEGORIES constant you are still holding onto  
instances of that old class, that no longer has any methods. You could  
get round this if it was defined in your category.rb file

Personally I’d probably have a Category.all\_categories method which  
would return cached data

Fred

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 18, 2008, 6:22pm UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/7 "2008-02-18T18:22:11Z")

</div>

On Feb 18, 2008, at 16:27 , Xavi C. wrote:

> I changed the config.cache\_classes option to true in the development  
> environment (it’s set to false by default) and now the cache works, so  
> you’re right that the cache didn’t work because of the default class  
> reloading in development mode.
> 
> Fred, using a Category.all\_categories method, how would you store the  
> cached data? in a class variable? in a constant?

(Salut! 🙂 Just in case you are waiting for this, an idiom I normally  
use something like:

def self.all\_categories  
@@all\_categories ||= find(:all, :order =\> ‘name ASC’)  
end

So, you always use the class method in client code, and the method  
caches the result in a class variable via de ||= trick. Written this  
way category loading is delayed until needed (just a remark, it does  
not imply it is better).

– fxn

---

<div class="post-metadata">

**Author:** ![xavi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/8e8cbc/32.png) [@xavi](https://www.ruby-forum.com/u/xavi)\
**Post date:** [February 19, 2008, 11:19am UTC](https://www.ruby-forum.com/t/caching-database-data-that-doesnt-change/129318/8 "2008-02-19T11:19:18Z")

</div>

On 18 Feb 2008, at 15:27, Xavi C. wrote:

> 

I would do what Xavier said.
