erb
-Datei sehr bekannt vorkommen. Es ist eine Mischung
aus (beispielsweise) HTML und Ruby-Code. (erb
steht für
embedded
Ruby, also eingebettetes Ruby.)
Allerdings können wir eine solche erb
-Webseite nicht
einfach in das Verzeichnis public
legen, da dort
abgelegte Seiten 1:1 ausgeliefert werden und nicht durch einen
erb
-Parser gehen. Dummerweise müssen wir dafür jetzt
direkt mit dem MVC-Modell [20]anrücken. Wir brauchen einen Controller. Den können wir mit dem Befehl rails
generate controller anlegen. Schauen wir uns mal die Hilfe
an:MacBook:testproject xyz$ rails generate controller
Usage:
rails generate controller NAME [action action] [options]
Options:
[--skip-namespace] # Skip namespace (affects only isolated applications)
[--old-style-hash] # Force using old style hash (:foo => 'bar') on Ruby >= 1.9
-e, [--template-engine=NAME] # Template engine to be invoked
# Default: erb
-t, [--test-framework=NAME] # Test framework to be invoked
# Default: test_unit
[--helper] # Indicates when to generate helper
# Default: true
[--assets] # Indicates when to generate assets
# Default: true
Runtime options:
-f, [--force] # Overwrite files that already exist
-p, [--pretend] # Run but do not make any changes
-q, [--quiet] # Supress status output
-s, [--skip] # Skip files that already exist
Description:
Stubs out a new controller and its views. Pass the controller name, either
CamelCased or under_scored, and a list of views as arguments.
To create a controller within a module, specify the controller name as a
path like 'parent_module/controller_name'.
This generates a controller class in app/controllers and invokes helper,
template engine and test framework generators.
Example:
`rails generate controller CreditCard open debit credit close`
Credit card controller with URLs like /credit_card/debit.
Controller: app/controllers/credit_card_controller.rb
Functional Test: test/functional/credit_card_controller_test.rb
Views: app/views/credit_card/debit.html.erb [...]
Helper: app/helpers/credit_card_helper.rb
MacBook:testproject xyz$
rails generate controller CreditCard open debit credit closePasst aber nicht direkt für unseren Fall.
MacBook:testproject xyz$ rails generate controller Example test
create app/controllers/example_controller.rb
route get "example/test"
invoke erb
create app/views/example
create app/views/example/test.html.erb
invoke test_unit
create test/functional/example_controller_test.rb
invoke helper
create app/helpers/example_helper.rb
invoke test_unit
create test/unit/helpers/example_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/example.js.coffee
invoke scss
create app/assets/stylesheets/example.css.scss
MacBook:testproject xyz$
app/views/example/test.html.erb
. Schauen
wir uns diese nachfolgend an:MacBook:testproject xyz$ cat app/views/example/test.html.erb
<h1>Example#test</h1>
<p>Find me in app/views/example/test.html.erb</p>
MacBook:testproject xyz$
MacBook:testproject xyz$ rails server
=> Booting WEBrick
=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-04-24 10:13:48] INFO WEBrick 1.3.1
[2012-04-24 10:13:48] INFO ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0]
[2012-04-24 10:13:48] INFO WEBrick::HTTPServer#start: pid=57898 port=3000
http://0.0.0.0:3000/example/test
im Browser an:log/development.log
finden wir den
folgenden Eintrag:Started GET "/example/test" for 127.0.0.1 at 2012-04-24 10:14:18 +0200 Processing by ExampleController#test as HTML Rendered example/test.html.erb within layouts/application (1.9ms) Compiled example.css (9ms) (pid 57898) Compiled application.css (18ms) (pid 57898) Compiled jquery.js (4ms) (pid 57898) Compiled jquery_ujs.js (0ms) (pid 57898) Compiled example.js (160ms) (pid 57898) Compiled application.js (198ms) (pid 57898) Completed 200 OK in 305ms (Views: 304.2ms | ActiveRecord: 0.0ms)
localhost
(127.0.0.1) ein HTTP-GET-Request für die URI
„/example/test
“ rein. Die wurde dann
anscheinend vom Controller ExampleController
mit der Methode
test
als HTML gerendert. Zusätzlich wurde noch
ein Satz von CSS- und JavaScript-Dateien kompiliert (darauf gehen wir
später im Buch ein). Das Ganze hat hier ungefähr 305 ms gedauert.app/controllers
, und siehe da, dort ist
auch tatsächlich die entsprechende Datei
app/controllers/example_controller.rb.
MacBook:testproject xyz$ ls -l app/controllers/
total 16
-rw-r--r-- 1 xyz staff 80 Apr 24 09:43 application_controller.rb
-rw-r--r-- 1 xyz staff 69 Apr 24 10:11 example_controller.rb
MacBook:testproject xyz$
class ExampleController < ApplicationController def test end end
ExampleController
stammt vom
ApplicationController
ab und enthält aktuell genau eine
Methode namens test
. Und diese Methode hat keinen
Inhalt./example/test
der Controller
ExampleController
und die Methode test
abzuarbeiten sind. Das wird nämlich nicht durch eine magische Logik,
sondern durch eine einfache Routing-Konfiguration gesteuert. Diese
finden Sie in der Datei config/routes.rb
in der
zweiten Zeile:MacBook:testproject xyz$ cat config/routes.rb | grep example
get "example/test"
MacBook:testproject xyz$
MacBook:testproject xyz$ rake routes
example_test GET /example/test(.:format) example#test
MacBook:testproject xyz$
public
hat immer eine höhere Priorität als eine Route in der
config/routes.rb
! Wenn wir also eine statische
Datei public/example/test
abspeichern würden, würde
die Route nicht mehr greifen.Erb
-Seiten können Ruby-Code enthalten. Damit
kann programmiert werden, und damit können diese Seiten dynamischen
Inhalt bekommen.irb
aus:MacBook:testproject xyz$ irb 1.9.3p194 :001 > 1 + 1 => 2 1.9.3p194 :002 > exit MacBook:testproject xyz$
erb
-Datei
app/views/example/test.html.erb
füllen wir wie
folgt:<h1>Erste Versuche mit erb</h1> <p>Addition: <%= 1 + 1 %> </p>
<%=
und einem %>
eingeschlossen. Es
können nur Strings ausgegeben werden.irb
nach, ob es wirklich ein
Fixnum ist:MacBook:testproject xyz$ irb 1.9.3p194 :001 > 1.class => Fixnum 1.9.3p194 :002 > (1 + 1).class => Fixnum 1.9.3p194 :003 > exit MacBook:testproject xyz$
test.html.erb
), die nicht bereits ein String sind,
automatisch mit der Methode .to_s
aufzurufen, welche per
Konvention immer den Inhalt des Objektes in einen String konvertiert.
Noch mal kurz ins irb
:MacBook:testproject xyz$ irb 1.9.3p194 :001 > (1 + 1) => 2 1.9.3p194 :002 > (1 + 1).class => Fixnum 1.9.3p194 :003 > (1 + 1).to_s => "2" 1.9.3p194 :004 > (1 + 1).to_s.class => String 1.9.3p194 :005 > exit MacBook:testproject xyz$
.html.erb
-Datei gibt es zusätzlich zu den
HTML-Elementen zwei Arten von Ruby-Code-Anweisungen:<%
…
%>
print
oder
puts
).<%=
…
%>
raw(string)
realisieren..to_s
hat oder das Objekt selber schon
ein String ist, kann man es als Ergebnis im View innerhalb einer
<%= …
%>
Kapselung
ausgeben.app/views/example/test.html.erb
wie
folgt:<p>Schleife von 0 bis 5: <% (0..5).each do |i| %> <%= "#{i}, " %> <% end %> </p>
<!DOCTYPE html> <html> <head> <title>Testproject</title> <link href="/assets/application.css?body=1" media="all" rel="stylesheet" type="text/css" /> <link href="/assets/example.css?body=1" media="all" rel="stylesheet" type="text/css" /> <script src="/assets/jquery.js?body=1" type="text/javascript"></script> <script src="/assets/jquery_ujs.js?body=1" type="text/javascript"></script> <script src="/assets/example.js?body=1" type="text/javascript"></script> <script src="/assets/application.js?body=1" type="text/javascript"></script> <meta content="authenticity_token" name="csrf-param" /> <meta content="TDIallkBmGrMzsL6TC8Chet4r/X1yLK0tthFmIig4+E=" name="csrf-token" /> </head> <body> <p>Schleife von 0 bis 5: 0, 1, 2, 3, 4, 5, </p> </body> </html>
F: | Ich verstehe gar nichts. Mit dem Ruby-Code komme ich
nicht zurecht. Können Sie das noch mal erklären? |
A: | Kann es sein, dass Sie Kapitel 2, Ruby-Grundlagen nicht komplett durchgearbeitet
haben? Bitte nehmen Sie sich die Zeit dafür. Sonst macht hier
das alles keinen Sinn. |
F: | Ich verstehe den Ruby-Code und die HTML-Ausgabe.
Allerdings verstehe ich nicht, warum drum herum noch HTML-Code
gerendert wurde, den ich gar nicht geschrieben habe. Woher
kommt der, und kann ich ihn beeinflussen? |
A: | Sehr gute Frage! Dazu kommen wir sofort (siehe „Layouts“). |
erb
werden Sie jetzt Stück
für Stück erlernen. Es handelt sich dabei nicht um Zauberei.erb
-Datei im Verzeichnis
app/views/example/
bildet nur den Kern der späteren
HTML-Seite. Per Default wird immer eine automatisch generierte
app/views/layouts/application.html.erb
drum herum
gerendert. Schauen wir uns die mal an:MacBook:testproject xyz$ cat app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Testproject</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
MacBook:testproject xyz$
<%= yield %>
wird hier die View-Datei
inkludiert. Die drei Zeilen mit den Stylesheets und dem JavaScript
lassen wir erst mal so, wie sie sind. Damit werden default CSS- und
JavaScript-Dateien eingebaut.app/views/layouts/application.html.erb
bietet Ihnen
die Möglichkeit, das Grund-Layout für die gesamte Rails-Applikation
festzulegen. Wenn Sie als Header für jede Seite ein
<hr>
und darüber einen Text eintragen wollen, dann
können Sie das zwischen dem <%= yield %>-
und dem
<body>
-Tag machen:<!DOCTYPE html>
<html>
<head>
<title>Testproject</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<p>Ein Test.</p>
<hr>
<%= yield %>
</body>
</html>
MacBook:testproject xyz$
app/views/layouts/
noch andere Layouts anlegen und
diese je nach Situation anwenden, aber lassen wir das erst mal. Wichtig
ist, dass Sie die Grundidee verstehen.@
an.
Wer sich nicht mehr 100 % sicher ist, welche Variable welchen
Geltungsbereich (Scope) hat,
der sollte ganz fix noch mal einen Blick in „Gültigkeitsbereich (Scope) von
Variablen“ werfen.app/controllers/example_controller.rb
sieht so
aus:class ExampleController < ApplicationController
def test
@current_time = Time.now
end
end
app/views/example/test.html.erb
können wir dann auf
diese Instance-Variable zurückgreifen:<p>
Die aktuelle Uhrzeit ist
<%= @current_time %>
</p>
to_s
angewendet.app/views/example/
Verzeichnis abgespeichert.
Allerdings muss der Dateiname mit einem Unterstrich (Underscore = _
)
anfangen.app/views/example/_footer.html.erb
den folgenden
Inhalt:<hr> <p> Copyright 2009 - <%= Date.today.year %> beim Osterhasen </p>
app/views/example/test.html.erb
verändern wir wie folgt und fügen mit dem Befehl render
das Partial
ein:<p>Schleife von 0 bis 5:
<% (0..5).each do |i| %>
<%= "#{i}, " %>
<% end %>
</p>
<%= render "footer" %>
app/views/example
:MacBook:testproject xyz$ ls -l app/views/example
total 8
-rw-r--r-- 1 xyz staff 0 Apr 24 11:03 _footer.html.erb
-rw-r--r-- 1 xyz staff 81 Apr 24 10:33 test.html.erb
MacBook:testproject xyz$
_
) am
Anfang und ohne die .erb-
und .html
-Endung angegeben. Aber die wirkliche
Datei muss im Dateinamen mit einem Unterstrich anfangen und auch am
Ende mit der .erb
- und
.html
-Endung aufhören.app/views
eingebunden werden. So können Sie für
wiederkehrende und übergreifende Inhalte beispielsweise ein Verzeichnis
app/views/shared
einrichten und dort eine Datei
_footer.html.erb
anlegen. Das Einbetten im
erb
-Code würde dann mit folgender Zeile
erfolgen:<%= render "shared/footer" %>
app/views/layouts/application.html.erb
.app/views/example/_footer.html.erb
einbauen:<hr />
<p>
Copyright <%= start_year %> - <%= Date.today.year %> beim Osterhasen
</p>
app/views/example/test.html.erb
wie
folgt:<p>Schleife von 0 bis 5: <% (0..5).each do |i| %> <%= "#{i}, " %> <% end %> </p> <%= render 'footer', :start_year => '2000' %>
http://0.0.0.0:3000/example/test
aufrufen, so sehen wir die 2000:<hr /> <p> Copyright <% if defined? start_year %> <%= start_year %> - <% end %> <%= Date.today.year %> beim Osterhasen </p>
<%= render 'footer',
:start_year => '2000' %>
und mit <%= render
'footer' %>
aufrufen.locals
.<%= render :partial => "footer", :locals => { :start_year => '2000' } %>
http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
finden Sie die Doku von Ruby on Rails zum Thema Partials.