Reputation: 8392
I have a Rails app which allows users to create unlimited number of static pages (I store these pages in postgres database), because these pages are statics I would like to use page caching, but I am not sure what's the limit number/size of caching pages in Rails, can I cache unlimited number of pages ?
Upvotes: 0
Views: 304
Reputation: 42799
@MikelLindsaar 's answer is good but kinda too much work for something that could be handled easier, ActiveRecord objects have a method called cache_key
that auto generates a unique key for each record, if the record gets touched or updated, the generated key will be different, this key is used for generating the whole view caching key, which is a function that has a lot of parameters, like the object id, updated_at (from the cache_key
), and the view's hash ( the cache gets invalidated if the view file is updated, not just the db), so there's no worry about any stale data, all you need to do would be:
The controller
class PagesController < ApplicationController::Base
def show
@page = Page.find(params[:id])
end
end
The view
<% cache @page do %>
<%# Render your page here %>
<% end %>
if you have multiple pages that use the same page object you could use a compound cache key, something like this for example
<% cache(prefix: 'page/show', page: @page) %>
and rails will handle the generation of the caching key.
More info about this over here http://guides.rubyonrails.org/caching_with_rails.html#fragment-caching
Upvotes: 1
Reputation: 251
we do this on our main company blog at https://reinteractive.net.
What you probably want to do is do fragment caching on the show action of the page you want to cache. There are some pitfalls to this, the biggest of which is expiring the cache if the underlying page changes.
It works like this:
In the routes.rb
file:
AppName::Application.routes.draw do
get "page/:id" => "pages#show"
end
In the controller (app/controllers/pages_controller.rb
):
class PagesController < ApplicationController::Base
def show
@page = Page.find(params[:id])
end
end
Note here in the controller you are hitting the database on every request but this should be a really fast request with the correct index in place.
Then in the view (app/views/pages/show.html.erb
):
<% cache("pages/show/#{@page.id}-#{@page.updated_at.to_i}") do %>
<%# Render your complex page here %>
<% end %>
What you gain from caching a fragment like this is that the output of the rendering gets stored in the cache and if this page takes a while to render, you can get significant time savings, especially if it takes 100ms or more to render the page and all it's parts, you pay for it the first time, and then after that it loads in a few milliseconds.
Note we are checking the last update time of the page? This is so that if you want to expire this cache (and render again) all you need to do is call page.touch
on the page object to update is updated_at
time.
If you have any other objects that could also update (such as say a page.header_image
or something, then you can also put the updated_at on these related objects into the cache key as well, or expire them manually when you update the page.
An alternative to adding updated_at
into the cache key is expiring them in the model like this:
class Page < ActiveRecord::Base
after_save :expire_cache
def expire_cache
Rails.cache.delete("CACHE_KEY")
end
end
But this has it's own challenges.
Good luck!
Upvotes: 1