Your SlideShare is downloading. ×
0
Caching in a multi-
language environment
 Benjamin Krause <benjamin@omdb.org>
Caching in Rails
Caching in Rails
‣   Page Caching
‣   Action Caching
‣   Fragment Caching
Caching in Rails
‣ Page Caching
‣ ______________
  Action Caching
‣ Fragment Caching
Caching in Rails
    Page Caching           Fragment Caching

  routing                    routing               routing

...
Page Caching

               Webserver



File.exists?          !File.exists?



   __ _ ____
   ___ ___ _
   _ __ ____
  ...
Fragment Caching



Mongrel


Rendering   Fragment
             Cache
Caching in Rails
‣   No support for caching in different
    languages
‣   No support to expire all language-
    caches a...
Content Negotiation
let the user decide, what he wants to see
Content Negotiation
consists of format negotiation and language
                negotiation
a simple resource
http://www.omdb.org/movies/2062
Format Negotiation

> HTTP “Accept” Header
  Accept: text/xml,application/xml,
          application/xhtml+xml,text/html

...
Format Negotiation
http://www.omdb.org/movies/2062.html
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>...
Format Negotiation


class MoviesController < ApplicationController
  def show
    respond_to do |format|
      format.htm...
Language Negotiation


> HTTP “Accept-Language” Header
  Accept-Language: en-us,en;q=0.7,de;q=0.3

> Rails ignores the HTT...
Language Negotiation
Language Negotiation

http://www.omdb.org/movies/2062.html.en
Routing Error
no route found to match "/movies/2062.html.en"...
let’s fix that
  extending Rails
Language Routes
extending Rails to set language routes
Language Routes

#   Adding default routes for
#   GET /movies/<id>
#   GET /movies/<id>.<format>
#   PUT /movies/<id>
#  ...
Language Routes
There are several possible routes, how to add a
language parameter.
http://www.omdb.org/movies/2062.html?l...
Language Routes
There are several possible routes, how to add a
language parameter.
http://www.omdb.org/movies/2062.html?l...
Language Routes
# Taken from Rails 1.2.3
# /actionpack-1.13.3/lib/action_controller/resources.rb
# with slight modificatio...
Language Routes
# Taken from Rails 1.2.3
# /actionpack-1.13.3/lib/action_controller/resources.rb
# with slight modificatio...
Language Routes
# Taken from Rails 1.2.3
# /actionpack-1.13.3/lib/action_controller/resources.rb
# with slight modificatio...
Language Routes

#   Extending
#   ActionController::Resources::map_new_actions
#   ActionController::Resources::map_membe...
Language Routes

#   Extending
#   ActionController::Resources::map_new_actions
#   ActionController::Resources::map_membe...
Language Routes
http://www.omdb.org/movies/2062.html.en
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>...
Accept-Language
extending Rails to know about the requested
                  language
Accept-Language


# in environment.rb
#
# These are custom extensions, this is not part
# of Rails

AC = ActionController
...
Accept-Language

# Taken from Rails 1.2.3
# /actionpack-1.13.3/lib/action_controller/request.rb

# Returns the accepted MI...
Accept-Language
class ActionController::AbstractRequest
  def accepts_languages
    begin
      @accepts_languages ||=
   ...
Accept-Language
Accept-Language: fr
=> [ :fr, :en ]
Accept-Language: fr; q=1.0, en; q=0.5, fi; q=0.2
=> [ :fr, :en ]
Accept...
Accept-Language
class ActionController::AbstractRequest
  def language
    params[:lang] || accepts_languages.first
  end
...
Language Routes
http://www.omdb.org/movies/2062.html.en
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>...
Caching
view caching, that is
Page Caching
extending Rails to support language-based page
                    caching
Page Caching

               Webserver



File.exists?          !File.exists?



   __ _ ____
   ___ ___ _
   _ __ ____
  ...
Page Caching

class MoviesController < ApplicationController
  caches_page :show

  def show
    respond_to |format| do
  ...
Page Caching

   GET /movies/2062

          Mongrel




        caches_page



~/public/movies/2062.html
Page Caching

# Taken from Rails 1.2.3
# /actionpack-1.13.3/lib/action_controller/caching.rb

def cache_page(content = nil...
Page Caching

# Reimplementing the cache_page method

module ActionController::Caching::Pages
  def cache_page(content = n...
Page Caching

     GET /movies/2062

            Mongrel




          caches_page



~/public/movies/2062.html.en
Page Caching


curl http://www.omdb.org/movies/2062 
              -H 'Accept: application/xml'


=> ~/public/movies/2062....
Page Caching


curl http://www.omdb.org/movies/2062 
             -H 'Accept-Language: fr, en, de'


=> ~/public/movies/20...
Page Caching


curl http://www.omdb.org/movies/2062 
            -H 'Accept-Language: fr, en, de' 
            -H 'Accept:...
Apache
how-to use Apaches content negotiations
Apache

# Taken from
# http://mongrel.rubyforge.org/docs/apache.html

# Rewrite to check for Rails cached page
RewriteRule...
Apache


# Taken from
# http://bugs.omdb.org/browser/trunk/conf/webserver/apache.conf

# Perform content-negotiation and s...
Apache

Apache 2.2 mod_rewrite documentation:

%{LA-U:variable} can be used for look-aheads
which perform an internal (URL...
Apache
# Prefer text/html over other Accept Headers
# Simplified RewriteConditions
RewriteCond %{HTTP_ACCEPT} text/html
Re...
GET /movies/2062                      Apache

                                      Subrequest

                          ...
Apache



# Let the user change the language in your
# application

SetEnvIf Cookie "language=(..)" prefer-language=$1
Fragment Caching
extending Rails to support language-based
           fragment caching
Fragment Caching

<% cache do %>
  <div class="person">
    <div class="image">
      <%= img_tag image_url(cast.person.im...
Fragment Caching

   cached content




      MemCache
Fragment Caching

<% cache :lang => request.language do %>
  <div class="person">
    <div class="image">
      <%= img_ta...
Fragment Caching

<% cache :lang => request.language do %>
  <div class="person">
    <div class="image">
      <%= img_ta...
Fragment Caching


ActionController::Base.fragment_cache_store =
                     :mem_cache_store, "localhost"
Fragment Caching


ActionController::Base.fragment_cache_store =
              OMDB::Cache::FragmentCache.instance
Fragment Caching


ActionController::Base.fragment_cache_store =
              OMDB::Cache::FragmentCache.instance


# Set...
Fragment Caching

   cached content




      MemCache
Fragment Caching

           cached content




MemCache      MemCache      MemCache


  :fr           :de           :en
Fragment Caching

            cached content




Namespace      Namespace     Namespace


  :fr            :de           :...
Fragment Caching

http://www.omdb.org/movies/2062.html.fr




    MemCache   MemCache    MemCache


      :fr        :de  ...
Fragment Caching

http://www.omdb.org/movies/2062.html.de




    MemCache   MemCache    MemCache


      :fr        :de  ...
Fragment Caching

http://www.omdb.org/movies/2062.html.en




    MemCache   MemCache    MemCache


      :fr        :de  ...
Fragment Caching

# Delete the fragment for one language
expire_fragment :controller => 'movies',
                :action ...
Tests
how to test the views
Test Page Caching

def test_caching_show
  accept :xml
  # language is a custom extension
  language :de

  page = "/casts...
Test Page Caching

def test_expire_show
  accept :xml
  language :de

  page = "/casts/#{casts(:first).id}.xml.de"
  asser...
Test Fragment Caching
def test_expire_fragment
  accept :js
  language :en
  params = { :controller => 'casts',
          ...
Where to get the plugins
The plugins are available from

http://svn.omdb-beta.org/plugins/mlr
http://svn.omdb-beta.org/plu...
thank you
Upcoming SlideShare
Loading in...5
×

Caching in a multilanguage environment

2,172

Published on

Published in: Technology, News & Politics
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,172
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "Caching in a multilanguage environment"

  1. 1. Caching in a multi- language environment Benjamin Krause <benjamin@omdb.org>
  2. 2. Caching in Rails
  3. 3. Caching in Rails ‣ Page Caching ‣ Action Caching ‣ Fragment Caching
  4. 4. Caching in Rails ‣ Page Caching ‣ ______________ Action Caching ‣ Fragment Caching
  5. 5. Caching in Rails Page Caching Fragment Caching routing routing routing before filters before filters before filters controller controller controller CACHED rendering rendering parts CACHED after filters after filters after filters illustration by Tammo Freese
  6. 6. Page Caching Webserver File.exists? !File.exists? __ _ ____ ___ ___ _ _ __ ____ __ ___ __ Mongrel __ _ ____
  7. 7. Fragment Caching Mongrel Rendering Fragment Cache
  8. 8. Caching in Rails ‣ No support for caching in different languages ‣ No support to expire all language- caches at once ‣ No support for language-negotiation
  9. 9. Content Negotiation let the user decide, what he wants to see
  10. 10. Content Negotiation consists of format negotiation and language negotiation
  11. 11. a simple resource http://www.omdb.org/movies/2062
  12. 12. Format Negotiation > HTTP “Accept” Header Accept: text/xml,application/xml, application/xhtml+xml,text/html > Rails supports format negotiation > Rails allows you to request a format explicitly (extra routes)
  13. 13. Format Negotiation http://www.omdb.org/movies/2062.html <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Ratatouille</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> http://www.omdb.org/movies/2062.xml <?xml version="1.0" encoding="UTF-8"?> <movie> <name>Ratatouille</name> <abstract> Remy is a rat, with a talent and passion for cooking. He dreams of one day working in a real restaurant
  14. 14. Format Negotiation class MoviesController < ApplicationController def show respond_to do |format| format.html { render } format.xml { render :xml => @movie.to_xml } format.js { render :json => @movie.to_json } end end end
  15. 15. Language Negotiation > HTTP “Accept-Language” Header Accept-Language: en-us,en;q=0.7,de;q=0.3 > Rails ignores the HTTP Header > Rails doesn’t add language routes
  16. 16. Language Negotiation
  17. 17. Language Negotiation http://www.omdb.org/movies/2062.html.en Routing Error no route found to match "/movies/2062.html.en" with {:method=>:get} http://www.omdb.org/movies/2062.xml.de Routing Error no route found to match "/movies/2062.xml.de" with {:method=>:get}
  18. 18. let’s fix that extending Rails
  19. 19. Language Routes extending Rails to set language routes
  20. 20. Language Routes # Adding default routes for # GET /movies/<id> # GET /movies/<id>.<format> # PUT /movies/<id> # PUT /movies/<id>.<format> # ... map.resources :movies map.resources :people map.resources :casts
  21. 21. Language Routes There are several possible routes, how to add a language parameter. http://www.omdb.org/movies/2062.html?lang=de http://de.omdb.org/movies/2062.html http://www.omdb.org/de/movies/2062.html http://www.omdb.org/movies/2062.de.html http://www.omdb.org/movies/2062.html.de
  22. 22. Language Routes There are several possible routes, how to add a language parameter. http://www.omdb.org/movies/2062.html?lang=de http://de.omdb.org/movies/2062.html http://www.omdb.org/de/movies/2062.html http://www.omdb.org/movies/2062.de.html http://www.omdb.org/movies/2062.html.de
  23. 23. Language Routes # Taken from Rails 1.2.3 # /actionpack-1.13.3/lib/action_controller/resources.rb # with slight modifications to fit this slide :-) action_options = action_options_for("show", resource) map.named_route( "#{resource.name_prefix}#{resource.singular}", resource.member_path, action_options ) map.named_route( "f_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", action_options )
  24. 24. Language Routes # Taken from Rails 1.2.3 # /actionpack-1.13.3/lib/action_controller/resources.rb # with slight modifications to fit this slide :-) action_options = action_options_for("show", resource) { :conditions => { :method => :get }, :requirements => { :id map.named_route( => /[^/;.,?]+/ }, :action => "show" } "#{resource.name_prefix}#{resource.singular}", resource.member_path, action_options ) map.named_route( "f_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", action_options )
  25. 25. Language Routes # Taken from Rails 1.2.3 # /actionpack-1.13.3/lib/action_controller/resources.rb # with slight modifications to fit this slide :-) action_options = action_options_for("show", resource) { :conditions => { :method => :get }, :requirements => { :id map.named_route( => /[^/;.,?]+/ }, :action => "show" } "#{resource.name_prefix}#{resource.singular}", resource.member_path, action_options ) map.named_route( "f_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", action_options ) /movies/:id
  26. 26. Language Routes # Extending # ActionController::Resources::map_new_actions # ActionController::Resources::map_member_actions # and others to support a language parameter map.named_route( "fl_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format.:lang", action_options )
  27. 27. Language Routes # Extending # ActionController::Resources::map_new_actions # ActionController::Resources::map_member_actions # and others to support a language parameter map.named_route( "fl_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format.:lang", action_options ) { :conditions => { :method => :get }, :requirements => { :id => /[^/;.,?]+/ :lang => /^fr|de|en$/ }, :action => "show" }
  28. 28. Language Routes http://www.omdb.org/movies/2062.html.en <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Ratatouille</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> http://www.omdb.org/movies/2062.xml.de <?xml version="1.0" encoding="UTF-8"?> <movie> <name>Ratatouille</name> <abstract> Remy is a rat, with a talent and passion for cooking. He dreams of one day working in a real restaurant
  29. 29. Accept-Language extending Rails to know about the requested language
  30. 30. Accept-Language # in environment.rb # # These are custom extensions, this is not part # of Rails AC = ActionController AC::AbstractRequest.default_language = :en AC::AbstractRequest.acceptable_languages = :fr, :de, :en
  31. 31. Accept-Language # Taken from Rails 1.2.3 # /actionpack-1.13.3/lib/action_controller/request.rb # Returns the accepted MIME type for the request def accepts @accepts ||= if @env['HTTP_ACCEPT'].to_s.strip.empty? [ content_type, Mime::ALL ] else Mime::Type.parse(@env['HTTP_ACCEPT']) end end
  32. 32. Accept-Language class ActionController::AbstractRequest def accepts_languages begin @accepts_languages ||= @env['HTTP_ACCEPT_LANGUAGE'].split(",").collect {|l| l.gsub(/;.*$/, '').gsub(/-.*$/,'').downcase.to_sym }.push(default_language).uniq @accepts_languages.delete_if { |l| !acceptable_languages.include?(l) } rescue NoMethodError @accepts_languages = default_language.is_a?(Array) ? default_language : [ default_language ] end end end
  33. 33. Accept-Language Accept-Language: fr => [ :fr, :en ] Accept-Language: fr; q=1.0, en; q=0.5, fi; q=0.2 => [ :fr, :en ] Accept-Language: en-us,en;q=0.7,de;q=0.3 => [ :en, :de ] Accept-Language: fi, es => [ :en ]
  34. 34. Accept-Language class ActionController::AbstractRequest def language params[:lang] || accepts_languages.first end end class ApplicationController before_filter :set_language def set_language @language = session[:lang] || request.language # for Globalize: # @language = Locale.set(@language) # for Gettext: # params[:lang] = @language unless params[:lang] end end
  35. 35. Language Routes http://www.omdb.org/movies/2062.html.en <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Ratatouille</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> http://www.omdb.org/movies/2062.xml.de <?xml version="1.0" encoding="UTF-8"?> <movie> <name>Ratatouille</name> <abstract> Eine Gourmet-Ratte muss so einiges erleiden, um ihre Lust auf exquisite Speisen befriedigen zu können.
  36. 36. Caching view caching, that is
  37. 37. Page Caching extending Rails to support language-based page caching
  38. 38. Page Caching Webserver File.exists? !File.exists? __ _ ____ ___ ___ _ _ __ ____ __ ___ __ Mongrel __ _ ____
  39. 39. Page Caching class MoviesController < ApplicationController caches_page :show def show respond_to |format| do format.html { render } format.xml { render :xml => @movie.to_xml } format.js { render :json => @movie.to_json } end end end
  40. 40. Page Caching GET /movies/2062 Mongrel caches_page ~/public/movies/2062.html
  41. 41. Page Caching # Taken from Rails 1.2.3 # /actionpack-1.13.3/lib/action_controller/caching.rb def cache_page(content = nil, options = {}) return unless perform_caching && caching_allowed self.class.cache_page(content || response.body, url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))) end
  42. 42. Page Caching # Reimplementing the cache_page method module ActionController::Caching::Pages def cache_page(content = nil, options = {}) return unless perform_caching && caching_allowed self.class.cache_page(content || response.body, url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format], :lang => request.language))) end end
  43. 43. Page Caching GET /movies/2062 Mongrel caches_page ~/public/movies/2062.html.en
  44. 44. Page Caching curl http://www.omdb.org/movies/2062 -H 'Accept: application/xml' => ~/public/movies/2062.xml.en
  45. 45. Page Caching curl http://www.omdb.org/movies/2062 -H 'Accept-Language: fr, en, de' => ~/public/movies/2062.html.fr
  46. 46. Page Caching curl http://www.omdb.org/movies/2062 -H 'Accept-Language: fr, en, de' -H 'Accept: application/xml' => ~/public/movies/2062.xml.fr
  47. 47. Apache how-to use Apaches content negotiations
  48. 48. Apache # Taken from # http://mongrel.rubyforge.org/docs/apache.html # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
  49. 49. Apache # Taken from # http://bugs.omdb.org/browser/trunk/conf/webserver/apache.conf # Perform content-negotiation and send to mongrel # if not cached. RewriteCond %{DOCUMENT_ROOT}/%{LA-U:REQUEST_URI} !-f RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
  50. 50. Apache Apache 2.2 mod_rewrite documentation: %{LA-U:variable} can be used for look-aheads which perform an internal (URL-based) sub-request to determine the final value of variable.
  51. 51. Apache # Prefer text/html over other Accept Headers # Simplified RewriteConditions RewriteCond %{HTTP_ACCEPT} text/html RewriteCond %{SCRIPT_FILENAME} !.html$ RewriteCond %{IS_SUBREQ} 'false' RewriteRule ^/(.*)$ /%{SCRIPT_FILENAME}.html [QSA] # Perform content-negotiation and send to mongrel # if not cached. RewriteCond %{DOCUMENT_ROOT}/%{LA-U:REQUEST_URI} !-f RewriteCond %{IS_SUBREQ} 'false' RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
  52. 52. GET /movies/2062 Apache Subrequest Apache /movies/2062.html.en Content Negotiation File.exists? !File.exists? __ ___ __ _ __ __ __ __ ___ __ __ _ _ __ ___ __ Mongrel ___ __ _ _ _ __ __ _ _ __
  53. 53. Apache # Let the user change the language in your # application SetEnvIf Cookie "language=(..)" prefer-language=$1
  54. 54. Fragment Caching extending Rails to support language-based fragment caching
  55. 55. Fragment Caching <% cache do %> <div class="person"> <div class="image"> <%= img_tag image_url(cast.person.image) %> </div> <strong> <%= link_to cast.person.name, person_url(cast.person) %> </strong> </div> <% end %>
  56. 56. Fragment Caching cached content MemCache
  57. 57. Fragment Caching <% cache :lang => request.language do %> <div class="person"> <div class="image"> <%= img_tag image_url(cast.person.image) %> </div> <strong> <%= link_to cast.person.name, person_url(cast.person) %> </strong> </div> <% end %>
  58. 58. Fragment Caching <% cache :lang => request.language do %> <div class="person"> <div class="image"> <%= img_tag image_url(cast.person.image) %> </div> <strong> <%= link_to cast.person.name, person_url(cast.person) %> </strong> </div> <% end %>
  59. 59. Fragment Caching ActionController::Base.fragment_cache_store = :mem_cache_store, "localhost"
  60. 60. Fragment Caching ActionController::Base.fragment_cache_store = OMDB::Cache::FragmentCache.instance
  61. 61. Fragment Caching ActionController::Base.fragment_cache_store = OMDB::Cache::FragmentCache.instance # Setting the default MemCache server OMDB::Cache::MemCacheStore.servers = 'localhost'
  62. 62. Fragment Caching cached content MemCache
  63. 63. Fragment Caching cached content MemCache MemCache MemCache :fr :de :en
  64. 64. Fragment Caching cached content Namespace Namespace Namespace :fr :de :en
  65. 65. Fragment Caching http://www.omdb.org/movies/2062.html.fr MemCache MemCache MemCache :fr :de :en
  66. 66. Fragment Caching http://www.omdb.org/movies/2062.html.de MemCache MemCache MemCache :fr :de :en
  67. 67. Fragment Caching http://www.omdb.org/movies/2062.html.en MemCache MemCache MemCache :fr :de :en
  68. 68. Fragment Caching # Delete the fragment for one language expire_fragment :controller => 'movies', :action => 'show', :id => 2062, :lang => :en # delete the fragment for all languages expire_fragment :controller => 'movies', :action => 'show', :id => 2062,
  69. 69. Tests how to test the views
  70. 70. Test Page Caching def test_caching_show accept :xml # language is a custom extension language :de page = "/casts/#{casts(:first).id}.xml.de" assert_cached_page( page ) do get :show, :id => casts(:first).id assert_response :success end end
  71. 71. Test Page Caching def test_expire_show accept :xml language :de page = "/casts/#{casts(:first).id}.xml.de" assert_no_cached_page( page ) do put :update, :id => casts(:first).id, :job => Job.composer.id assert_response :success end end
  72. 72. Test Fragment Caching def test_expire_fragment accept :js language :en params = { :controller => 'casts', :id => casts(:first).id, :template => 'cast' } assert_cached_fragment( params ) do put :update, :id => casts(:first).id, :job => Job.composer.id assert_template 'cast' end assert_no_cached_fragment( params ) do casts(:first).save end end
  73. 73. Where to get the plugins The plugins are available from http://svn.omdb-beta.org/plugins/mlr http://svn.omdb-beta.org/plugins/mlcache There will be an official announcement on http://blog.omdb-beta.org/
  74. 74. thank you
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×