Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to clear cache in Rails without sweepers

Observers and Sweepers are removed from Rails 4. Cool. But what is the way to cache and clear cache then ?

I read about russian doll caching. It nice and all but it only concerns the view rendering cache. It doesn't prevent the database from being hit.

For instance:

<% cache @product do %>
  Some HTML code here
<% end %>

You still need to get @product from the db to get its cache_key. So page or action caching can still be useful to prevent unnecessary load.

I could use some timeout to clear the cache sometimes but what for if the records didn't change ?

At least with sweepers you have control on that aspect. What is/will be the right way to do cache and to clear it ?

Thanks ! :)

like image 875
Happynoff Avatar asked Dec 11 '12 15:12

Happynoff


People also ask

How do I flush Rails cache?

clear in the Rails console to clear the cache. Unfortunately there is no way (yet) to do it from the command line. We can add a rake task that will do this for us. Then we can execute ./bin/rake cache:clear and clear the Rails cache from the command line.

What is cache sweeper in Rails?

Cache sweeping is a mechanism which allows you to get around having a ton of expire_{page,action,fragment} calls in your code. It does this by moving all the work required to expire cached content into na ActionController::Caching::Sweeper class.

Which of the following caching techniques is are available in Rails?

This is an introduction to three types of caching techniques: page, action and fragment caching. By default Rails provides fragment caching. In order to use page and action caching you will need to add actionpack-page_caching and actionpack-action_caching to your Gemfile .

Where does Rails store cache?

Rails (as of 2.1) provides different stores for the cached data created by action and fragment caches. Page caches are always stored on disk. Rails 2.1 and above provide ActiveSupport::Cache::Store which can be used to cache strings.


1 Answers

Welcome to one of the two hard problems in computer science, cache invalidation :)

You would have to handle that manually since the logic for when a cached object, unlike a cached view which can be simply derived from the objects it displays, should be invalidated is application and situation dependent.

You goto method for this is the Rails.cache.fetch method. Rails.cache.fetch takes 3 arguments; the cache key, an options hash, and a block. It first tries to read a valid cache record based on the key; if that key exists and hasn’t expired it will return the value from the cache. If it can’t find a valid record it instead takes the return value from the block and stores it in the cache with your specified key.

For example:

@models = Rails.cache.fetch my_cache_key do
  Model.where(condition: true).all
end

This will cache the block and reuse the result until something (tm) invalidates the key, forcing the block to be reevaluated. Also note the .all at the end of the method chain. Normally Rails would return an ActiveRecord relation object that would be cached and this would then be evaluated when you tried to use @models for the first time, neatly sidestepping the cache. The .all call forces Rails to eager load the records and ensure that it's the result that we cache, not the question.

So now that you get all your cache on and never talk to the database again we have to make sure we cover the other end, invalidating the cache. This is done with the Rails.cache.delete method that simply takes a cache key and removes it, causing a miss the next time you try to fetch it. You can also use the force: trueoption with fetch to force a re-evaluation of the block. Whichever suits you.

The science of it all is where to call Rails.cache.delete, in the naïve case this would be on update and delete for a single instance and update, delete, create on any member for a collection. There will always bee corner cases and they are always application specific, so I can't help you much there.

I assume in this answer that you will set up some sane cache store, like memcached or Redis.

Also remember to add this to config/environments/development.rb:

config.cache_store = :null_store

or you development environment will cache and you will end up hairless from frustration.

For further reference read: Everyone should be using low level caching in Rails and The rails API docs

It is also worth noting that functionality is not removed from Rails 4, merely extracted into a gem. If you need or would like the full features of the sweepers simply add it back to your app with a gem 'rails-observers' line in your Gemfile. That gem contains both the sweepers and observers that where removed from Rails 4 core.

I hope that helpt you get started.

like image 125
Jonas Schubert Erlandsson Avatar answered Oct 14 '22 20:10

Jonas Schubert Erlandsson