Skip to content

codelearn-org/rails-cache-example-app

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#Cache in Rails#

Web cache is a mechanism used for storing web documents such as HTML pages and images to reduce the bandwidth and server load. In Ruby on Rails there are mainly 3 types of caching used namely Page caching, Action Caching and Fragment Caching

#Page Caching#

In page caching whenever a request is sent by a user to the server, the web server would check for the generated cached page and if that exists it would be served. Hence the rails app won't have to process it again thereby saving bandwidth and avoids load on the server. This type of caching is lightning fast, but one main disadvantage of this is that this can't be used for caching every page. As the requests don't go to the rails app, the authentication and access restrictions using before_filter wont work if page caching is used.

Consider an example where a page relies on the user's settings. If we cache this page, another user won't get the customized settings but only be able to get the cached copy of the page.

eg for Page caching:

Class UserController < ActionController

  caches_page :profile

  def profile
    @user = current_user
  end

end

To expire the cache when an update is made, we will have to call an expire_page action eg :

Class UserController < ActionController

  caches_page :profile

  def profile
    @user = current_user
  end

  def update
    expire_page :action=> profile
  end

end

#Action Caching#

In action caching the disadvantages of page caching won't be a problem as all the requests will be sent to the rails app via the web-server Hence the authentication and access restrictions using the before_filters can be applied before serving a page. Action Caching is done similar to page caching in terms of code. eg:

class UserController < ActionController

  before_filter :authenticate
  caches_action :profile

  def profile
    @user = current_user
  end

  def update
    expire_action :action => :profile
  end

end

#Fragment Caching#

Fragment Caching is mainly used for dynamic pages. In this type of caching fragments of a page can be cached and expired.

Consider an example in which an article is posted to a blog and a reader wants to post a comment to it. Since the article is the same this can be cached while the comments will be dynamic in nature as he posts his comment that should be displayed. In this case we can use fragment caching for posts

eg:

<% cache do %>
  <%= render article %>
<% end %>

<% @article.comments.each do |comments| %>
  <%= comments.user_name %>
  <%= comments.user_comment %>
<% end %>

Here the article would be cached while the comments wont.

#SQL Caching#

SQL Caching will cache any SQL results performed by the Active Records or Data mappers so that if the same query is doesn't hit the database again and thereby decreasing the load time. Eg:

class ArticleController < ActionController

  def index
    @artilces = Article.all

    # Run the same query again
    @articles = Article.all # will pull the data from the memory and not from DB
  end

end

#Russian Doll Caching (Rails 4)#

In Russian Doll Caching nested fragment caches are used, so that the caches can be reused again. In Russian Doll caching, if a fragment change at the top level then only that fragment is expired instead of expiring the whole fragment. Thus we can reuse that cache.

Eg:

class Article < ActiveRecord::Base
  has_many :comments
end

class Comments < ActiveRecord::Base
  belongs_to :articles, touch: true
end

The touch option for belongs_to model will make sure that whenever the article changes the cache will be updated in the comments too.

To demonstrate the concepts of caching in rails I have made a simple blog hack. Here the index action in home_controller.rb will render home page if the users aren't signed in else the signed in users will be redirected to the articles index action, where the articles will be displayed. In order to perform page caching, just add caches_page to the the home_controller.rb

Eg:

class HomeController < ApplicationController
  caches_page :index

  def index
    redirect_to articles_path if user_signed_in?
  end

end

An example of action caching can be found on the articles_controller.rb, where we can perform caching on the index, show actions. Here as long as a new article is posted, edited or destroyed the contents of the index and show will remain the same. Hence we action caching would be the best in this case.

Eg:

class ArticlesController < ApplicationController
  before_filter :authenticate_user!
  caches_action :index, :show

  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

end

But we need to make sure that the cache is expired whenever an article changes. So we also need to add expire_action to actions in articles_controller.rb

Eg:

class ArticlesController < ApplicationController
  before_filter :authenticate_user!
  caches_action :index, :show

  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def create
    @article = Article.new(params[:article])
    if @article.save
      expire_action :action => [:index,:show] #expire the cache whenever a new article is posted
    end
  end

end

The index action also uses the SQL caching mechanism in rails. The Article.all will run an Active Record query to fetch all the articles from the database and will create a cache for this query. If the same query is repeated the cached result will be used instead of querying the database again.

#What happens when inappropriate caching is used ?#

Consider the case, when page caching was used for the index action instead of action caching in the articles_controller.rb. Whenever a user clicks on the index link, a cached copy if the index page would be rendered to him, even if he is not signed in. Thus the purpose of authentication will be lost if inappropriate caching methods are used for your actions.

You can always try out the app in codelearns playground. Just fork the repo. Navigate to the app directory (cd <app_folder>), bundle install to make sure all dependencies are satisfied. Then simply start the server using the rails s command and you will have the app running in your browser.

You can find the whole app at github. and is hosted on heroku. PS: The Demo App was created using scaffolded code and is just meant for demonstrating the caching mechanism in rails. User authentication and UI wasn't give much importance. If someone has spare time and is willing to contribute the pull-requests are always welcome :)

--
Manu S Ajith
GitHub | Twitter

About

A simple hack to demonstrate caching in rails

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 96.7%
  • JavaScript 1.8%
  • CoffeeScript 1.5%