Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pre-building view cache in Rails

Is there a way to pre-build a page cache without calling the actual page via a http request?

I looked at solutions like this and this, but these don't generate the cache.

I have a relatively complicated view, and want to cache the entire thing. I want to pre-build this cached version in the application so when a user actually hits it, it will already be there.

Thanks

like image 872
user99168 Avatar asked Jul 26 '11 21:07

user99168


People also ask

What are view cache in Rails?

1.1 Page Caching Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the web server (i.e. Apache or NGINX) without having to go through the entire Rails stack. While this is super fast it can't be applied to every situation (such as pages that need authentication).

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.

What is view caching?

Views caching¶The Views module is a query builder. Any view the module creates queries your database one or more times. Creating views can result in a large number of database queries for any given page load. By default, Views does not cache any of its queries or data.

Does Rails cache use Redis?

Rails 5.2 introduced built-in Redis cache store, which allows you to store cache entries in Redis.


1 Answers

We had a need to do something similar from a rake task -- we had a partial that would need to display a very long list of entities (~700) which were somewhat context specific and which, due to a series of database structure issues and custom sorting criteria, would easily take > 25 seconds to render the first time before going into cache> This would often time out because our HTTP servers were set to terminate HTTP requests with no response after 30 seconds, and pre-caching this custom list was a solution.

What you need to do is create an instance of ActiveController::Base, or of one of your controllers if you need helper methods or other entities, then pass its lookup_context reference to a new instance of ActionView.Renderer.

In our rake task, we did the following

namespace :rake_for_time_consuming_nonsense do
  task :pre_cache_long_list do
    PreCacher.pre_fetch_partials
  end
end

class PreCacher
  def self.pre_fetch_partials
    the_controller = ActionController::Base.new
    # Set any instance variables required by your partial in the controller, 
    # they will be passed to the partial with the view_context reference
    the_controller.instance_variable_set "@cache_key", cache_key
    the_controller.instance_variable_set "@the_object", MyModel.first

    view_renderer = ActionView::Renderer.new the_controller.lookup_context
    view_renderer.render the_controller.view_context, {partial: 'my_model/the_partial', layout: false}
  end
end

This works in Rails 3.2.13.

like image 101
jfrprr Avatar answered Oct 24 '22 17:10

jfrprr