But... nothing is every easy!
I may look simple, but I encountered several problems
1. Conflicts with GetText
We use GetText for the translations on FilmAmora. We like it because there are free poEditor apps on every platform and we can easily send off the files to whomever to be translated.
The problem comes with this line:
require 'gettext/rails'
That you need to have to fire up some of the Rails-specific GetText stuff. This is all fine - it has been working for quite some time. But, when I tried to cache our Genres like this:
def self.all_cached(language)
key = "genres_#{language}"
Rails.cache.fetch(key) {Genre.find(:all).sort_by {|genre| genre.get_description}.reject {|g| g.get_films_count == 0}}
end
Here is the result:
undefined method `cache' for GetText::Rails:Module
What?!?! Yes, it seems that GetText::Rails will hide Rails. This is, quite frankly, SHIT. So, after a long time poking around I have discovered that you need to do this:
def self.all_cached(language)
key = "genres_#{language}"
::Rails.cache.fetch(key) {Genre.find(:all).sort_by {|genre| genre.get_description}.reject {|g| g.get_films_count == 0}}
end
Yippee! It will all work now, right?
Wrong.
2. Class != Class
I hit refresh the first time and wow was I excited! I saw lines like this in the log:
Cache write (will save 0.59562): genres_es
Woo hoo! Look at all the time I will save!
So I hit refresh.
undefined method `get_description' for #<Genre id: 1, description: "Action and Adventure", order_by: 2>
What?!?!
I am using the 'default' memory store. Something is going funny with retrieving objects from it. I never solved this problem.
If I do this in the console:
>> @genres = Genre.all_cached("es")
>> @genres = Genre.all_cached("es")
I see this in the log:
Cache write (will save 0.51974): genres_es
Cache hit: genres_es ({})
And I can do this:
>> @genres[0].get_description("es")
So what is going on in my web app? I have no idea. It seems that the class retrieved from the memory cache is incomplete in some way. get_description is not an accessor, it does go off and get the translation, but... so what? it is still a method.
This had me stumped!
3. File Store no worky
So I added this to development.rb:
config.cache_store = :file_store, '/cache_store'
I ended up getting this:
undefined method `get_description' for #<String:0x5459f0c>
Ok, I am tired of this now.
4. MemCached
Everyone is talking about using MemCached for this kind of thing. Now, I know developers and we are a lazy bunch. My guess is that this whole caching stuff has been written with MemCache in mind and screw anything else (see points 2 and 3 above).
So I installed MemCache and changed the line in the development.rb to be this:
config.cache_store = :mem_cache_store
I restarted the server and hit refresh. Trying to contain my excitement I saw a properly rendered page.
I hit refresh again.
undefined class/module Subgenre
For CHRIST'S SAKE!
After another web-scouring exercise I discovered a solution.
My method now looks like this:
def self.all_cached(language)
key = "genres_#{language}"
Subgenre
::Rails.cache.fetch(key) {Genre.find(:all).sort_by {|genre| genre.get_description}.reject {|g| g.get_films_count == 0}}
end
And guess what? It works. Of course it now means running memcache on my local machine and installing it on the production box. But I've saved .52 seconds! It took 3 hours to get to the solution, so I figure in only 350 web page hits I will make it back.
Oh, of course I was already caching the html on the server for most things, but this is a little tidier.