Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort des Fachgutachters
Einleitung
1 Einführung
2 Installation
3 Erste Schritte
4 Einführung in Ruby
5 Eine einfache Bookmarkverwaltung
6 Test-Driven Development
7 Rails-Projekte erstellen
8 Templatesystem mit ActionView
9 Steuerzentrale mit ActionController
10 Datenbankzugriff mit ActiveRecord
11 E-Mails verwalten mit ActionMailer
12 Nützliche Helfer mit ActiveSupport
13 Ajax on Rails
14 RESTful Rails und Webservices
15 Rails mit Plug-ins erweitern
16 Performancesteigerung
17 Sicherheit
18 Veröffentlichen einer Rails-Applikation auf einem Server
Ihre Meinung?

Spacer
 <<   zurück
Ruby on Rails 2 von Hussein Morsy, Tanja Otto
Das Entwickler-Handbuch
Buch: Ruby on Rails 2

Ruby on Rails 2
geb., mit DVD
699 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-89842-779-1
Online bestellenPrint-Version jetzt bestellen
* versandkostenfrei in (D) und (A)
Pfeil 16 Performancesteigerung
  Pfeil 16.1 Einführung
  Pfeil 16.2 Page-Caching
  Pfeil 16.3 Action-Caching
  Pfeil 16.4 Fragment-Caching
  Pfeil 16.5 Caching von CSS- und JavaScript-Dateien
  Pfeil 16.6 Caching mit memcached
  Pfeil 16.7 Zusammenfassung


Rheinwerk Computing - Zum Seitenanfang

16.2 Page-Caching  Zur nächsten ÜberschriftZur vorigen Überschrift

Page-Caching ist die einfachste Art des Caching in Rails. Es basiert auf dem Prinzip, dass die gesamte Seite in einer Datei zwischengespeichert wird.


Rheinwerk Computing - Zum Seitenanfang

Grundlagen  Zur nächsten ÜberschriftZur vorigen Überschrift

Wenn ein Seite zum ersten Mal aufgerufen wird, wird sie zunächst von Rails verarbeitet. Dies erfordert folgende Schritte:

  1. Routing

    Die URL wird verarbeitet, und nach den definierten Routingregeln werden daraus der entsprechende Controller und die passende Action aufgerufen.

  2. Ausführung der Action im Controller

    Im Controller wird die entsprechende Action ausgeführt, um z. B. Parameter auszulesen, ActiveRecord-Befehle auszuführen und die Ergebnisse in einer Instanzvariablen einem Template zur Verfügung zu stellen. Die gegebenenfalls erforderlichen Datenbankzugriffe sind in den meisten Fällen der zeitaufwendigste Teil der Verarbeitung.

  3. Verarbeitung des Templates

    Im Template schließlich wird der HTML-Code generiert.

  4. Speichern des HTML-Codes als Datei

    Wenn das Caching aktiviert ist, wird der HTML-Code nicht nur direkt an den Client (Webbrowser) weitergeleitet, sondern auch als Datei im Verzeichnis public gespeichert.

Beim nächsten Aufruf wird nicht mehr der Railsprozess durchlaufen, sondern das statische HTML-Dokument aus dem Verzeichnis public direkt an den Client ausgeliefert. Ihre Website ist in diesem Fall genauso performant wie eine Website, die auf rein statischen Webseiten basiert.

public

Der Rails-Server schaut bei jedem Zugriff im Verzeichnis public nach, ob das entsprechende Dokument vorhanden ist. Wenn es vorhanden ist, so wird das HTML-Dokument direkt an den Client geschickt. Ansonsten wird der Railsverarbeitungsprozess gestartet. Angenommen, der Webserver erhält die Anfrage für die URL http://http://www.url.de/products/234 , dann überprüft er, ob die Datei public/products/234.html vorhanden ist. Es ist zu beachten, dass products ein Verzeichnis ist. Ist die Datei vorhanden, wird sie direkt an den Client ausgeliefert.

Im folgenden Diagramm wird der Ablauf des Caching verdeutlicht.

Abbildung  Grundprinzip des Page-Caching


Rheinwerk Computing - Zum Seitenanfang

Caching im Controller aktivieren  Zur nächsten ÜberschriftZur vorigen Überschrift

Das Page-Caching wird pro Action (Methode) im Controller festgelegt. Es kommen jedoch nur die Actions für das Page-Caching in Frage, die auch nur für die Anzeige von Daten zuständig sind. Dies sind in der Regel nur die Index-Action für die Anzeige aller Datensätze und die Show-Action für die Anzeige eines Datensatzes im Detail. Formulare sollten deshalb nicht im Cache gespeichert werden.

caches_page

Das Page-Caching wird im Controller mit dem Befehl caches_page :action1, :action2, ... für die entsprechenden Actions aktiviert. Die Aktivierung des Page-Caching für die Actions :index und :show im Employees-Controller unseres Beispiels aus Kapitel 3 können Sie wie folgt umsetzen:

class EmployeesController < ApplicationController
  caches_page :index, :show
  ...
end

Rheinwerk Computing - Zum Seitenanfang

Einstellungen  Zur nächsten ÜberschriftZur vorigen Überschrift

In den Environment-Konfigurationsdateien wird mit der Einstellung

config.action_controller.perform_caching = true/false

das Caching aktiviert bzw. deaktiviert. Diese Einstellung betrifft sowohl das Page-Caching als auch das Action- und Fragment-Caching.

Standardmäßig hat Rails drei Konfigurationsdateien:

  • Konfigurationsdatei für die Entwicklungsumgebung:
    In der Datei config/environments/development.rb werden Einstellungen für die Entwicklungsumgebung vorgegeben. Wenn Sie die Applikation lokal mit ruby script/server starten, werden die Einstellungen aus der Development-Umgebung geladen. Hier ist das Caching standardmäßig deaktiviert:
    ...
    config.action_controller.perform_caching  = false
    ...
  • Konfigurationsdatei für die Testumgebung:
    Die Testumgebung wird in der Datei config/environments/test.rb konfiguriert. Auch hier ist das Caching standardmäßig deaktiviert. Da die Testumgebung für die Ausführung der Testklassen verwendet wird, sollte das Caching hier nicht aktiviert werden.
  • Konfigurationsdatei für die Produktionsumgebung:
    Die Produktionsumgebung wird in der Regel auf dem Webserver verwendet. Deshalb ist das Caching in der Konfigurationsdatei config/environments/production.rb aktiviert:
    config.action_controller.perform_caching = true

Rheinwerk Computing - Zum Seitenanfang

Beispiel  Zur nächsten ÜberschriftZur vorigen Überschrift

Um Ihnen das Caching anhand eines Beispiels zu zeigen, erstellen wir eine kleine Applikation zur Verwaltung von Produkten und aktivieren im Products-Controller das Caching.

  1. Rails-Projekt erstellen

    rails caching_demo
    cd caching_demo

  2. Ressource »products« erstellen

    ruby script/generate scaffold product name:string \
    price:float

  3. Migration zum Erstellen der Tabellen ausführen

    rake db:migrate

  4. Im Controller Caching für Index- und Show-Action aktivieren
    class ProductsController < ApplicationController
      caches_page :index, :show
      ...
    
    end

Starten Sie anschließend den lokalen Server mit ruby script/server, rufen Sie die Seite http://localhost:3000/products auf, und geben Sie ein paar Beispielprodukte ein.

Abbildung  http://localhost:3000/products

Wir aktivieren zu Testzwecken das Caching in der Konfigurationsdatei für die Entwicklungsumgebung.

Listing  config/environments/development.rb

config.action_controller.perform_caching =
true 

Nachdem wir Änderungen an der Konfigurationsdatei vorgenommen haben, müssen wir den lokalen Server erneut starten ( + und dann erneut ruby script/server).

Wenn wir die Seiten http://localhost:3000/products und http://localhost:3000/products/1 aufrufen, werden folgende Dateien durch das Caching aktiviert:

Abbildung  mono{public}-Verzeichnis mit den Cache-Dateien

In dem Konsolen-Fenster, in dem der lokale Server gestartet wurde, bzw. im Log-File kann man beobachten, dass es beim erneuten Laden der Seiten zu keinerlei Aktivität kommt.


Rheinwerk Computing - Zum Seitenanfang

Löschen von Cache-Dateien  Zur nächsten ÜberschriftZur vorigen Überschrift

Problem

Wenn wir einen weiteren Datensatz über den Link New product hinzufügen, fällt auf, dass das neue Produkt nicht in der Liste der Produkte http://localhost:3000 angezeigt wird. Das gleiche Problem tritt auch auf, wenn wir einen Datensatz verändern. Die Änderung wird wegen des Caching weder auf der Index- noch auf der Show-Seite angezeigt. Es gibt verschiedene Möglichkeiten, den Cache zu löschen. Das Löschen von Cache-Dateien wird auch als Cache Expire bezeichnet.

Manuelles Löschen von Cache-Dateien

Löschen

Der Cache kann z. B. leicht gelöscht werden, indem Sie einfach die entsprechende Datei im Verzeichnis public (z. B. public/flights.html) löschen. Dann werden die Daten wieder frisch aus der Datenbank gelesen und die Cache-Dateien neu erstellt.

Ein manuelles Löschen ist jedoch nicht praktikabel. Wir hätten gerne, dass bei jeder Änderung eines Datensatzes oder beim Hinzufügen eines neuen Datensatzes automatisch die betroffenen Cache-Dateien gelöscht werden. Wenn z. B. die Produkt-Informationen zum Produkt mit der ID 1 geändert werden, müssen die Cache-Dateien gelöscht werden:

  • public/products.html
  • public/products/1.html

Löschen von Cache-Dateien mit dem »expire_page«-Befehl

Der Befehl expire_page(pfad_zur_datei) löscht die unter der URL angegebene Datei (vorausgesetzt, die Datei ist auf dem Server vorhanden).

Beispiel für die Verwendung von expire_page:

  • expire_page(/products)
    Löscht die Datei public/products.html.
  • expire_page(/products/2)
    Löscht die Datei public/products/2.html.

Anstatt den Pfad anzugeben, ist es praktischer, Methoden zu verwenden.

Der scaffold-Generator hat in der Datei config/routes.rb den Befehl map.resources :products hinzugefügt. Dadurch wird eine Reihe von Methoden definiert, mit deren Hilfe die Pfade angegeben werden können. Der Aufruf des expire_page -Befehls kann dann wie folgt erfolgen:

  • expire_page(products_path)
    Löscht die Datei public/products.html.
  • expire_page(product_path(@product))
    Löscht die Datei public/products/2.html, vorausgesetzt, @product ist ein Produkt-Datensatz mit der ID 2.

Einsatz im Controller

Wenn ein Datensatz bearbeitet, hinzugefügt oder gelöscht wird, müssen die entsprechenden Cache-Dateien gelöscht werden. Wir zeigen den Einsatz des expire_page -Befehls am Beispiel des Products-Controller. Es werden jedoch nur die Methoden gelistet, für die der Befehl hinzugefügt wurde:

class ProductsController < ApplicationController

  caches_page :index, :show

  def new
    @product = Product.new
    expire_page(products_path)
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @product }
    end
  end

  def create
    @product = Product.new(params[:product])

    respond_to do |format|
      if @product.save
        expire_page(products_path)
        flash[:notice] = 'Product was successfully created.'
        ...
      end
    end
  end

  def update
    @product = Product.find(params[:id])

    respond_to do |format|
      if @product.update_attributes(params[:product])
        expire_page(products_path)
        expire_page(product_path(@product))
        flash[:notice] = 'Product was successfully updated.'
      ...
      end
    end
  end

  def destroy
    @product = Product.find(params[:id])
    @product.destroy
    expire_page(products_path)
    expire_page(product_path(@product))

    respond_to do |format|
      format.html { redirect_to(products_url) }
      format.xml  { head :ok }
    end
  end
end

caches_page :index

Um das Page-Caching für den Products-Controller zu aktivieren, haben wir den Befehl caches_page :index, :show verwendet, der angibt, welche Actions im Cache gespeichert werden sollen. Unschön ist jedoch, dass wir den Befehl expire_page verstreut in den einzelnen Actions eingefügt haben. Besser wäre, wenn die einzelnen Actions überhaupt keinen Code für das Caching beinhalten würden, da das Caching kein Bestandteil des Algorithmus der einzelnen Actions sein soll.

Dies kann durch den Einsatz von Sweepern verbessert werden.

Einsatz von Sweepern

Sweeper (zu Deutsch Straßenkehrer) sind spezielle Klassen, die für das Löschen von Cache-Dateien zuständig sind. Ein Sweeper kann ein oder mehrere Models beobachten, ob ein Datensatz gespeichert oder gelöscht wurde.

Wir definieren die nachfolgende Klasse in der Datei product_sweeper.rb, die wir im Verzeichnis app/models anlegen:

Listing  app/models/product_sweeper.rb

class ProductSweeper < ActionController::Caching::Sweeper
  observe Product

  def after_save(product)
    expire_page(product_path(product))
    expire_page(products_path)
  end

  def after_destroy(product)
    expire_page(product_path(product))
    expire_page(products_path)
  end
end

In dieser Klasse wird nach jedem Speichern (after_save) und dem Löschen (after_destroy) eines Datensatzes im Model Product die Detailseite und die Listenansichts-Seite gelöscht.

Der Befehl observe legt fest, welche Models auf Änderungen beobachtet werden sollen. Es kann auch mehr als ein Model beobachtet werden, wie z. B. observe Product, Category.

Im folgenden Schritt refaktorisieren wir die Klasse, indem wir das DRY-Prinzip anwenden:

Listing  app/models/product_sweeper.rb

class ProductSweeper < ActionController::Caching::Sweeper
  observe Product

  def after_save(product)
    expire_products(product)
  end

  def after_destroy(product)
    expire_products(product)
  end

  private

  def expire_products(product)
    expire_page(product_path(product))
    expire_page(products_path)
  end
end

expire_page

Im Products-Controller benötigen wir nicht mehr den Befehl expire_page, sondern fügen lediglich den Befehl cache_sweeper am Anfang in Form einer Deklaration hinzu:

Listing  app/controllers/products_controller.rb

class ProductsController < ApplicationController

  caches_page :index, :show
  cache_sweeper :product_sweeper,
	        :only => [:update, :create, :destroy]

...
end

Der Cache-Sweeper product_sweeper wird nur für die Actions update, create und destroy aufgerufen, weil nur in diesen Actions Datensätze verändert werden.

Löschen von Cache-Dateien mit einem Rake-Task

Mit dem folgenden Rake-Task können alle Cache-Dateien leicht gelöscht werden. Dies ist z. B. praktisch, wenn Sie neue Daten direkt in die Datenbank importieren oder wenn Sie ganz sichergehen wollen, dass keine veralteten Daten angezeigt werden. Wir speichern dazu den folgenden Rake-Task in der Datei lib/tasks/cache.rake ab:

Listing  lib/tasks/cache.rake

desc "delete all products cache files"
task "cache:products:clear" do
  product_index = File.join(RAILS_ROOT,'public','products.html')
  product_dir = File.join(RAILS_ROOT,'public','products')
  rm_rf([product_index,product_dir])
end

rake -T

Der Rake-Task erscheint dann in der Liste aller Rake-Tasks (rake -T).

rake -T

rake cache:products:clear           # delete all products ...
rake db:abort_if_pending_migrations # Raises an error if  ...
rake db:charset                     # Retrieves the charse...
rake db:collation                   # Retrieves the collat...
...

Der Rake-Task kann mit rake cache:products:clear aufgerufen werden.


Rheinwerk Computing - Zum Seitenanfang

Cachen der Root-Page  topZur vorigen Überschrift

In jeder Applikation wird normalerweise eine Action eines Controllers als Root-Page bzw. Start-Seite der gesamten Website festgelegt.

In unserem Beispiel soll dies die Action index des Products-Controllers sein. Dazu gehen wir wie folgt vor:

  1. Den Products-Controller als Startseite festlegen

    Dazu wird in config/routes.rb der Products-Controller als Root-Route eingetragen:

    map.root :controller => 'products', :action => 'index'
    Die Angabe :acion => 'index' ist optional.

  2. Löschen der Datei public/index.html

    Die Datei public/index.html enthält die »Willkommen«-Seite von Rails.

index-Action

Die index -Action des Products-Controllers kann nun über die folgenden URLs aufgerufen werden:

  1. http://localhost:3000

    In diesem Fall wird die Cache-Datei public/index.html generiert.

  2. http://localhost:3000/products

    In diesem Fall wird die Cache-Datei public/products.html generiert.

Für das Löschen des Caches für die index -Action des Products-Controller müssen daher zwei Dateien gelöscht werden.

Eine Lösung besteht darin, im Sweeper die Datei public/index.html mit dem Löschbefehl FileUtils.rm_f zu entfernen. Im Gegensatz zu FileUtils.rm wird bei FileUtils.rm_f kein Fehler angezeigt, wenn die entsprechende Datei nicht vorhanden ist.

Listing  app/models/product_sweeper.rb

class ProductSweeper < ActionController::Caching::Sweeper
  observe Product

  def after_save(product)
    expire_products(product)
  end

  def after_destroy(product)
    expire_products(product)
  end

  private

  def expire_products(product)
    expire_page(product_path(product))
    expire_page(products_path)
    expire_index
  end

  def expire_index
    # index.html löschen
    index = File.join(RAILS_ROOT,'public','index.html')
    FileUtils.rm_f(index)
  end
end


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
 <<   zurück
  Zum Katalog
Zum Katalog: Ruby on Rails 2
Ruby on Rails 2
Jetzt bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Ruby on Rails 3.1






 Ruby on Rails 3.1


Zum Katalog: Responsive Webdesign






 Responsive Webdesign


Zum Katalog: Suchmaschinen-Optimierung






 Suchmaschinen-
 Optimierung


Zum Katalog: JavaScript






 JavaScript


Zum Katalog: Schrödinger lernt HTML5, CSS3 und JavaScript






 Schrödinger lernt
 HTML5, CSS3
 und JavaScript


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de