

Everyone should be using low level caching in Rails - robotmay
http://robotmay.com/post/23161612605/everyone-should-be-using-low-level-caching

======
wavesplash
Excellent. You may wish to mention that the default Rails.cache is a per-
process cache and doesn't work between instances / goes away at process death.

For Memcache users, configure Rails.cache to use Rails' built in
:memcache_store:

[http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemCa...](http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemCacheStore.html)

For Redis fans, try :redis_store:

<https://github.com/jodosha/redis-store>

This covers Rails 3 caching pretty well:

[http://broadcastingadam.com/2011/05/advanced_caching_in_rail...](http://broadcastingadam.com/2011/05/advanced_caching_in_rails)

Note for Rails 2: If I recall correctly, in Rails 2 fragment caching/action
caching still uses the filesystem even if you have a cache_store set.

~~~
pselbert
As a small addendum, I strongly recommend dalli
(<https://github.com/mperham/dalli>) over the default memcached library. It is
written by the former maintainer of the memcached gem, is smaller in size, up
to 20% faster, and most importantly to me, is actively maintained.

Most of that info is in the readme, btw.

------
rapind
If by everyone he means anyone who's reached a point in their application
where it's worth adding code and complexity in order to improve performance,
then yes this is useful (and I use it often).

<http://c2.com/cgi/wiki?PrematureOptimization>

~~~
robotmay
Agreed. Though I will admit to often prematurely optimising as I quite enjoy
performance tweaking :)

~~~
rapind
Yeah, guilty on occasion here too, but only if I find myself with too much
spare time.

------
jaylevitt
There used to be many model-caching plugins for Rails, but few if any made the
transition to Rails 3. The record-cache gem looks interesting and flexible,
though I haven't tried it:

<https://github.com/orslumen/record-cache>

~~~
rapind
IdentityMap is going to greatly reduce the need for model caching for the
majority of sites. High traffic sites with a lot of data will still benefit
from a distributed cache though.

[http://api.rubyonrails.org/classes/ActiveRecord/IdentityMap....](http://api.rubyonrails.org/classes/ActiveRecord/IdentityMap.html)

~~~
jaylevitt
That would be wonderful. Unfortunately, IdentityMap was disabled by default in
3.1 because it was incomplete, and it was pulled from 4.0 for a while due to
lack of development:

<https://github.com/rails/rails/pull/5261>

Though there is now a company volunteering to fund completion of the feature,
starting Real Soon Now:

<https://github.com/rails/rails/issues/5442>

IdentityMap would, obviously, be great. Though I didn't realize it could serve
as a replacement for model caching; didn't IdentityMap, like the query cache,
only last for the lifetime of a request? Or could it be persisted in the
Rails.cache of your choice for an arbitrary lifespan?

~~~
rapind
IdentityMap stores the model in memory for the process. Only storing for the
lifetime of a request wouldn't be terribly useful.

IdentityMap will be extremely useful for the majority of sites since they have
very low traffic, processor, and memory demands, and therefore it's unlikely
you'll have too many processes running using up their own memory containers.
Though you could argue these sites really don't need additional caching
anyways (they'd still respond slightly faster with IdentityMap).

For high traffic sites it'll still be useful to save some trips, but you'll
also want to implement and manage a distributed cache (for models, actions,
fragments, etc).

It's available and sort of works now. You just have to turn it on and be
mindful of how associations are handled. Still a work in progress.

------
bnorton
This is good information, but could you explain why you think that everyone
should use caching? You don't mention testing in this article so is it safe to
say that you don't? Do you have performance tests that show that the caching
actualy matters for you application workload?

~~~
robotmay
I do test for caching (though I must admit I write first, test later); I'll
write that up in a later post. Similarly, I'll put up some comparisons to show
the performance difference those changes have made :)

I think everyone should be caching as the speed of your page loads is fast
becoming an even more important factor in people using/enjoying your site.
Everyone (including myself) is getting more impatient in regards to page load
speed, and every little helps. Also, you never know when you'll hit the
frontpage on HN!

------
Jake232
Nice fist post. For anyone interested, he's another awesome guide to Rails
Caching. Worth a read too. -
[http://broadcastingadam.com/2011/05/advanced_caching_in_rail...](http://broadcastingadam.com/2011/05/advanced_caching_in_rails)

------
getsat
Good article. A few things:

Use "if" and "present?" instead of "unless" and "blank?". It's much easier to
parse mentally, especially for people who didn't write the code. :)

You don't need to use "self" to access latitude, longitude, updated_at, etc.
You only need to use it for assignment.

You don't need to call #to_s on the captured exception. When you interpolate
an object into a string, Ruby calls #to_s on the supplied object itself, e.g.,
"I am an #{Object}".

I'd probably also add a "has_posts" scope to Category and use that instead of
the #where call in ApplicationController.

~~~
robotmay
Thanks for the feedback!

I'll keep that in mind for the future; it's a bad habit of mine :D

I actually didn't realise you only needed that for assignment. That's going to
neaten up my code somewhat.

I normally don't put .to_s in strings like that, so I'm not entirely sure why
I did in that line.

Aye, I'd normally use a scope but I figured I'd write it out more verbosely
just for clarity :)

------
FabPelletier
Interesting tips, I'll be sure to try them out.

