13.4 RJS: Ruby-JavaScript 

Ruby-Code
Die meisten Ruby-Programmierer sind von ihrer Sprache so überzeugt, dass sie am liebsten alles in Ruby programmieren möchten. JavaScript gilt hingegen als unschön und sehr umständlich. Dank eines Ruby-JavaScript- Generators müssen Ruby-Entwickler JavaScript-Code nicht in JavaScript schreiben. Ruby-JavaScript wird mit RJS abgekürzt.
Mit folgenden Ruby-Befehlen kann z. B. die Meldung »Hallo Welt« nach einer Verzögerung von 4 Sekunden ausgegeben werden:
page.delay(4) do page.alert("Hallo Welt") end
Dieser Ruby-Code wird von Rails in folgenden JavaScript-Code übersetzt bzw. es wird folgender JavaScript-Code generiert:
try { setTimeout(function() {; alert("Hallo Welt");}, 4000); } catch (e) { alert('RJS error: n n' + e.toString()); alert('setTimeout(function() { n; nalert("Hallo Welt"); n}, 4000);'); throw e }
Neben den eigentlichen Befehlen für die Verzögerung und die Meldung ist im JavaScript-Code auch eine Fehlerbehandlungsroutine integriert.
RJS-Befehle einfügen 

RJS-Code wird entweder in einer Action eines Controllers eingesetzt oder in eine eigene Datei in dem Verzeichnis, in der auch die anderen Templates liegen, ausgelagert.
RJS in einer Datei
js.rjs
Die RJS-Befehle werden in Template-Dateien gepseichert, die so heißen wie die aufrufende Action, mit der Endung .js.rjs.
Listing app/views/demo/hello.js.rjs
page.alert("Hallo Welt")
Im Controller muss entsprechend angegeben werden, dass bei einer Ajax- Anfrage die RJS-Datei ausgeführt werden soll:
class DemoController < ApplicationController
def index
...
respond_to do |format|
format.js
end
end
end
respond_to
Der respond_to -Befehl erkennt, welches Format angefragt wurde. Dadurch ist es sogar möglich, dass dieselbe Action je nach Anfrage-Typ unterschiedlich reagiert. Im folgenden Beispiel wird bei einer HTML-Anfrage die Template-Datei index.html.erb ausgeführt. Bei einer XML-Anfrage wird der Befehl, der im Block angegeben ist, ausgeführt. Im Fall einer Ajax-Anfrage wird die Template-Datei index.js.rjs ausgeführt.
class DemoController < ApplicationController def index ... respond_to do |format| format.html format.xml { render :xml => @message.xml} format.js end end end
RJS direkt im Controller
Testzwecke
Es ist auch möglich, RJS-Befehle direkt im Controller auszuführen, ohne eine RJS-Datei zu erstellen. Diese Technik sollte jedoch hauptsächlich nur für Testzwecke angewendet werden, da der View, zu dem auch JavaScript- Befehle gehören, vom Controller zu trennen ist.
class DemoController < ApplicationController def index ... respond_to do |format| format.js do render :update do |page| page.alert("hello world") end end end end end
Aufrufen von RJS 

Link, Formular, Observer
Ajax-Anfragen werden in den meisten Fällen entweder per Link oder Formular ausgeführt. Es ist aber auch möglich, dass automatisch alle x Sekunden eine Anfrage ausgeführt wird oder dass eine Ajax-Anfrage ausgeführt wird, wenn Eingaben in einem Formular-Feld vorgenommen werden (sogenannter Observer ).
link_to_remote
Am einfachsten kann ein Ajax-Aufruf per Link erfolgen. Die Methode link_to_remote generiert JavaScript-Code, der sowohl für das Senden der Ajax-Anfrage als auch für das Empfangen der Ajax-Daten zuständig ist. Der Parameter :url gibt die URL der Ajax-Action an:
link_to_remote "Zeige Daten", :url => { :action => "show", :id => product.id }
remote_form_for und form_remote_tag
Formulardaten können auch per Ajax gesendet werden. Wie bei »normalen« Formularen gibt es eine Variante für Formulare mit Bezug zu einem Model (remote_form_for) und eine Variante für Formulare ohne Bezug zu einem Model (form_remote_tag).
Listing Ajax-Formular mit Bezug zu einem Model
<% remote_form_for :bookmark, :url => bookmarks_url do |f| %> ... <%= f.text_field :title %> ... <% end %>
Listing Ajax-Formular ohne Bezug zu einem Model
<% form_remote_tag :url => '/example' do %> ... <%= text_field_tag 'name' %> ... <% end %>
periodically_call_remote
Der Helper periodically_call_remote führt im folgenden Beispiel alle 60 Sekunden die Action news_ticker aus. Das ist z. B. praktisch, um auf einer Seite News-Meldungen oder Börsenkurse zu aktualisieren.
periodically_call_remote(:url =>{ :action=> 'news_ticker'}, :frequency => '60')
observe_field
Der View-Helper observe_field kann alle x Sekunden Formulareingaben an eine Action schicken. Die Zeit wird über die Option frequency eingestellt. Der Name des Formularfeldes, das »observiert« werden soll, wird über die Option :with angegeben:
<%= observe_field(:searchbox, :url => { :action => :live_search }), :frequency => 0.5, :with => 'query' %>
link_to_function
Sonderfall
Ein Sonderfall ist die Helper-Methode link_to_function, da hier direkt RJS-Befehle eingefügt werden können. Diese Methode ist zu bevorzugen, wenn Sie z. B. Elemente ein- bzw. ausblenden möchten, ohne dass Daten vom Server benötigt werden. In diesem Fall wird keine Ajax-Anfrage ausgeführt.
<%= link_to_function "Hello World", update_page {|page| page.alert('Hello World')} %>
Beispiel 

Im folgenden einfachen Beispiel soll durch einen Klick auf einen Link eine Text-Meldung in der Webseite angezeigt werden, ohne dass die Seite neu geladen wird.
Im Abschnitt »Ajax« in Kapitel »Eine einfache Bookmarkverwaltung« finden Sie ein ausführliches Beispiel zur Integration von Ajax in einer datenbankbasierten Webapplikation.
- Erstellung eines Rails-Projekts
Wir generieren zunächst ein neues Projekt.
rails ajax_demo
- Layout-Datei anlegen
Anschließend legen wir im Verzeichnis app/views/layouts die Lay- applicatiout- Datei application.html.erb an, in der der Rahmen für die ge- on.html.erb samte Applikation definiert wird. Im Head-Bereich werden die Java- Script-Dateien mit dem Befehl javascript_include_tag :defaults eingebunden.
Listing app/views/layout/application.html.erb
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang='en'> <head> <title>Ajax</title> <%= javascript_include_tag :defaults %> </head> <body> <%= yield %> </body> </html>
- Controller Helloworld mit Index-Seite erstellen
Wir erstellen zunächst einen Controller mit der Action index und der zugehörigen Template-Datei:
ruby script/generate controller helloworld index
- Action say_hello erstellen
Wir fügen im HelloworldController die Action say_hello hinzu, in der wir das RJS-Template laden wollen:
Listing /app/controllers/helloworld_controller.rb
class HelloworldController < ApplicationController def index end def say_hello @message = "Hello World" respond_to do |format| format.js end end end
- Link erstellen
In dem index -View legen wir einen Link an:
Listing app/views/helloworld/index.html.erb
<h1>Helloworld#index</h1> <%= link_to_remote "Hier klicken", :url => {:action => "say_hello"} %> <p id='message'>...</p>
- Ruby-JavaScript-Datei erstellen
Wir erstellen eine Ruby-JavaScript-Datei say_hello.js.rjs, die folgenden Ruby-Code enthält, der bei Ausführung der Datei in Java- Script-Code übersetzt wird:
Listing app/views/helloworld/say_hello.js.rjs
page.replace_html 'message', @message page.visual_effect(:highlight, 'message', :duration => 0.5)
Inhalt ersetzen
Die Methode replace_html ersetzt den Inhalt des HTML-Tags mit der ID message . In unserem Fall werden die drei Punkte innerhalb des <p> -Tags durch den Wert der Instanzvariablen @message, die im Controller gesetzt wurde, ersetzt.
Die Methode visual_effect wendet den Effekt highlight auf das HTML-Element mit der ID message an. In unserem Beispiel wird die Message Hello World kurz (0,5 Sekunden) aufblinken.
- Beispiel ausführen
Rufen Sie die URL http://localhost:3000/helloworld auf, und klicken Sie auf den Link.
Abbildung Hello World
Durch den Aufruf des Links, wird die Ruby-JavaScript-Datei ausgeführt, in JavaScript übersetzt und an den Browser geschickt, der sie dann ausführt.
Bei unserem Ansatz wird der JavaScript-Code auf dem Server generiert, was den Vorteil hat, dass wir Daten aus der Datenbank verwenden können.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.