Rails Tutorial DHBW-Heidenheim

Anwendung erzeugen

Eine neue Anwendung wird mit rails new [name] erzeugt. Dabei werden eine Reihe von Verzeichnissen und Dateien angelegt.


	noname:rs till$ rails new Beispiel -d mysql
	      create  
	      create  README
	      create  Rakefile
	      create  config.ru
	      create  .gitignore
	      create  Gemfile
	      create  app
	      create  app/controllers/application_controller.rb
	      create  app/helpers/application_helper.rb
	      create  app/mailers
	      create  app/models
	      create  app/views/layouts/application.html.erb
	      create  config
	      create  config/routes.rb
	      create  config/application.rb
	      create  config/environment.rb
	      create  config/environments
	      create  config/environments/development.rb
	      create  config/environments/production.rb
	      create  config/environments/test.rb
	      create  config/initializers
	      create  config/initializers/backtrace_silencers.rb
	      create  config/initializers/inflections.rb
	      create  config/initializers/mime_types.rb
	      create  config/initializers/secret_token.rb
	      create  config/initializers/session_store.rb
	      create  config/locales
	      create  config/locales/en.yml
	      create  config/boot.rb
	      create  config/database.yml
	      create  db
	      create  db/seeds.rb
	      create  doc
	      create  doc/README_FOR_APP
	      create  lib
	      create  lib/tasks
	      create  lib/tasks/.gitkeep
	      create  log
	      create  log/server.log
	      create  log/production.log
	      create  log/development.log
	      create  log/test.log
	      create  public
	      create  public/404.html
	      create  public/422.html
	      create  public/500.html
	      create  public/favicon.ico
	      create  public/index.html
	      create  public/robots.txt
	      create  public/images
	      create  public/images/rails.png
	      create  public/stylesheets
	      create  public/stylesheets/.gitkeep
	      create  public/javascripts
	      create  public/javascripts/application.js
	      create  public/javascripts/controls.js
	      create  public/javascripts/dragdrop.js
	      create  public/javascripts/effects.js
	      create  public/javascripts/prototype.js
	      create  public/javascripts/rails.js
	      create  script
	      create  script/rails
	      create  test
	      create  test/fixtures
	      create  test/functional
	      create  test/integration
	      create  test/performance/browsing_test.rb
	      create  test/test_helper.rb
	      create  test/unit
	      create  tmp
	      create  tmp/sessions
	      create  tmp/sockets
	      create  tmp/cache
	      create  tmp/pids
	      create  vendor/plugins
	      create  vendor/plugins/.gitkeep
	noname:rs till$

Gestartet wird die Anwendung mit dem Befehl rails server. Dieser startet einen Webserver, der als default den Port 3000 verwendet. Dort ist die Anwendung verfügbar.


	noname:rs till$ cd Beispiel
	noname:Beispiel till$ rails server
	=> Booting WEBrick
	=> Rails 3.0.3 application starting in development on http://0.0.0.0:3000
	=> Call with -d to detach
	=> Ctrl-C to shutdown server
	[2011-01-24 11:33:03] INFO  WEBrick 1.3.1
	[2011-01-24 11:33:03] INFO  ruby 1.8.7 (2009-06-12) [universal-darwin10.0]
	[2011-01-24 11:33:03] INFO  WEBrick::HTTPServer#start: pid=9744 port=3000

Ruft man nun diese Anwendung im Browser auf, wird eine default Seite angezeigt (die natürlich geändert werden kann. Es handelt sich hier um die Datei index.html im Unterverzeichnis public).

Datenbank konfigurieren

Verwendet man eine sqlite Datenbank (bei rails new keinen Datenbank-Parameter angeben) ist dieser Schritt nicht nötig.

Soll eine andere Datenbank verwendet werden - hier im Beispiel mysql - muss die Datenbank-Konfiguration angepasst werden. Insbesondere müssen die Anmeldeinformationen für den Datenbankserver angegeben werden. Diese Informationen stehen in der Datei database.yml im Unterverzeichnis config. Hier müssen normalerweise die entsprechenden Eintr&aum;ge gemacht werden.

Für unser Beispiel braucht hier nichts geändert zu werden, da rails als default den Benutzer root ohne Kennwort einträgt. In unserem Beispielsystem ist dies korrekt, in einem "echten" System hätte der Benutzer root vermutlich ein Kennwort.


	# MySQL.  Versions 4.1 and 5.0 are recommended.
	#
	# Install the MySQL driver:
	#   gem install mysql2
	#
	# And be sure to use new-style password hashing:
	#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
	development:
	  adapter: mysql2
	  encoding: utf8
	  reconnect: false
	  database: Beispiel_development
	  pool: 5
	  username: root
	  password:
	  host: localhost

In einem produktiven System müssten hier ggf. Einträge angepasst werden. Im folgenden Abschnitt ist eine solche Konfiguration gezeigt. Hier ist auch noch der socket Parameter gesetzt. Als default wird hier /tmp/mysql.sock verwendet. Dies funktioniert unter MAC OS X nicht, hier ist dieser socket üblicherweise im Verzeichnis /var/mysql zu finden.

Achten Sie darauf, auch die Einträge in den Abschnitten test und production anzupassen. rails erzeugt drei Datenbanken, eine für die Entwicklung, eine für den Test und eine für den Betrieb.


	# MySQL.  Versions 4.1 and 5.0 are recommended.
	#
	# Install the MySQL driver:
	#   gem install mysql2
	#
	# And be sure to use new-style password hashing:
	#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
	development:
	  adapter: mysql2
	  encoding: utf8
	  reconnect: false
	  database: Beispiel_development
	  pool: 5
	  username: till
	  password: geheim
	  host: localhost
	  socket: /var/mysql/mysql.sock	

Stimmt die Datenbank-Konfiguration, können die Datenbanken angelegt werden:


	noname:Beispiel till$ rake db:create
	(in /Users/till/rs/Beispiel)
	noname:Beispiel till$

Schaut man in mysql nach, findet man die angelegten Datenbanken:


	noname:Beispiel till$ mysql -u root
	Welcome to the MySQL monitor.  Commands end with ; or \g.
	Your MySQL connection id is 34
	Server version: 5.5.0-m2 MySQL Community Server (GPL)

	Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

	mysql> show databases;
	+----------------------+
	| Database             |
	+----------------------+
	| information_schema   |
	| Beispiel_development |
	| Beispiel_test        |
	| mysql                |
	+----------------------+
	10 rows in set (0.38 sec)

	mysql>

rake erzeugt hier zwei Datenbanken, Beispiel_development und Beispiel_test. Diese beiden werden für die Entwicklung einer Anwendung benötigt. Die Produktionsumgebung (üblicherweise Beispiel_production) würde angelegt, wenn bei der rake task der Parameter RAILS_ENV=production mitgegeben würde.

Objekte mit scaffolding erzeugen

Beginnen wir mit der Entwicklung unserer Anwendung. Wir wollen ein einfaches Social Network entwickeln, eine Online Kontaktbörse. Das Analysis-Level Datenmodell soll so aussehen:

Beginnen wir mit der Tabelle Person. Zunächst müssen wir die entsprechende Tabelle in der Datenbank anlegen und den Code zum Zugriff darauf (Personen anlegen, ändern, suchen usw.) erzeugen. Im ersten Schritt lassen wir dies von rails automatisch erledigen. Später werden wir sehen, wie diese einzelnen Schritte manuell ausgeführt werden köhrt werden können.

Zunächst müssen wir festlegen, welche Typen die Attribute einer Person haben sollen. In unserem Fall sind das bis auf die PLZ alles Strings. Die PLZ stellen wir als integer Zahl dar.


noname:Beispiel till$ rails generate scaffold Person Nickname:string Name:string Vorname:string email:string 
Geburtsdatum:string PLZ:integer Geschlecht:string Ich:string IchKurz:string
	      invoke  active_record
	      create    db/migrate/20110124135102_create_people.rb
	      create    app/models/person.rb
	      invoke    test_unit
	      create      test/unit/person_test.rb
	      create      test/fixtures/people.yml
	       route  resources :people
	      invoke  scaffold_controller
	      create    app/controllers/people_controller.rb
	      invoke    erb
	      create      app/views/people
	      create      app/views/people/index.html.erb
	      create      app/views/people/edit.html.erb
	      create      app/views/people/show.html.erb
	      create      app/views/people/new.html.erb
	      create      app/views/people/_form.html.erb
	      invoke    test_unit
	      create      test/functional/people_controller_test.rb
	      invoke    helper
	      create      app/helpers/people_helper.rb
	      invoke      test_unit
	      create        test/unit/helpers/people_helper_test.rb
	      invoke  stylesheets
	      create    public/stylesheets/scaffold.css
	noname:Beispiel till$

Wie man sieht, werden eine Menge Dateien erzeugt, insbesondere eine Migration, ein Model (app/models/person.rb), ein Controller (app/views/people_controller.rb) und eine Reihe von Views (app/views/people/*). Die Migration enthält die notwendigen Informationen, um die Datenbank auf den aktuellen Stand zu bringen. In unserem Fall also von nichts zur Tabelle Person.

Diese Migration kann mit dem Befehl rake db:migrate ausgeführt werden. Dabei wird dann die Tabelle Person angelegt.


	noname:Beispiel till$ rake db:migrate
	(in /Users/till/rs/Beispiel)
	==  CreatePeople: migrating ===================================================
	-- create_table(:people)
	   -> 0.1897s
	==  CreatePeople: migrated (0.1898s) ==========================================

	noname:Beispiel till$
	noname:Beispiel till$
	noname:Beispiel till$ mysql -u root
	mysql> use Beispiel_development;
	mysql> show tables;
	+--------------------------------+
	| Tables_in_beispiel_development |
	+--------------------------------+
	| people                         |
	| schema_migrations              |
	+--------------------------------+
	2 rows in set (0.00 sec)

	mysql> describe people;
	+--------------+--------------+------+-----+---------+----------------+
	| Field        | Type         | Null | Key | Default | Extra          |
	+--------------+--------------+------+-----+---------+----------------+
	| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
	| Nickname     | varchar(255) | YES  |     | NULL    |                |
	| Name         | varchar(255) | YES  |     | NULL    |                |
	| Vorname      | varchar(255) | YES  |     | NULL    |                |
	| email        | varchar(255) | YES  |     | NULL    |                |
	| Geburtsdatum | varchar(255) | YES  |     | NULL    |                |
	| PLZ          | int(11)      | YES  |     | NULL    |                |
	| Geschlecht   | varchar(255) | YES  |     | NULL    |                |
	| Ich          | varchar(255) | YES  |     | NULL    |                |
	| IchKurz      | varchar(255) | YES  |     | NULL    |                |
	| created_at   | datetime     | YES  |     | NULL    |                |
	| updated_at   | datetime     | YES  |     | NULL    |                |
	+--------------+--------------+------+-----+---------+----------------+
	12 rows in set (0.00 sec)

	mysql>

Mit dem mysql-Client lässt sich der Erfolg dieser Operation betrachten: Die Tabelle people in der Datenbank Beispiel_development wurde erzeugt. Sie enthält die Attribute, die bei der Erzeugung des scaffolds (genauer des models) angegeben wurden. Zusätzlich findet man noch einige von rails automatisch erzeugte Attribute: id, der Primärschlüssel identifiert eine Person und wird automatisch verwaltet. Die Attribute created_at und updated_at werden von rails ebenfalls automatisch angelegt und verwaltet. Dort wird Buch darüber geführt, wann Datensätze erzeugt und geändert wurden.

Mit dieser erzeugten Anwendung kann bereits gearbeitet werden, sie enthält im Prinzip alles, was benötigt wird, um Personen zu verwalten. Unter der URL http://localhost:3000/people kann eine Liste der existierenden Personen aufgerufen werden bzw. neue Personen angelegt, bearbeitet und gelöscht werden, nachdem der Server wieder mit rails server gestartet wurde.

Eine zweite Tabelle dazu ... Messages

Eine Anwendung besteht im Allgemeinen aus mehr als einer Klasse/Tabelle. So auch hier. Wir machen also mit einer zweiten Tabelle weiter, mit den Messages. Unsere Benutzer sollen Nachrichten austauschen können, diese werden in der Tabelle Messages gespeichert. Eine Nachricht gehört immer einer Person, dem Empfänger. Wir erzeugen wieder mit dem scaffold-Mechanismus das Model, den Controller und die Views und legen mit rake db:migrate die Tabelle messages an.


		noname:Beispiel till$ rails generate scaffold Message Absender:string Betreff:string Text:string 
		Datum:datetime person:references
		      invoke  active_record
		      create    db/migrate/20110124142849_create_messages.rb
		      create    app/models/message.rb
		      invoke    test_unit
		      create      test/unit/message_test.rb
		      create      test/fixtures/messages.yml
		       route  resources :messages
		      invoke  scaffold_controller
		      create    app/controllers/messages_controller.rb
		      invoke    erb
		      create      app/views/messages
		      create      app/views/messages/index.html.erb
		      create      app/views/messages/edit.html.erb
		      create      app/views/messages/show.html.erb
		      create      app/views/messages/new.html.erb
		      create      app/views/messages/_form.html.erb
		      invoke    test_unit
		      create      test/functional/messages_controller_test.rb
		      invoke    helper
		      create      app/helpers/messages_helper.rb
		      invoke      test_unit
		      create        test/unit/helpers/messages_helper_test.rb
		      invoke  stylesheets
		   identical    public/stylesheets/scaffold.css
		noname:Beispiel till$
		noname:Beispiel till$ rake db:migrate
		(in /Users/till/rs/Beispiel)
		==  CreateMessages: migrating =================================================
		-- create_table(:messages)
		   -> 0.2027s
		==  CreateMessages: migrated (0.2029s) ========================================
	

Wiederum können wir uns davon überzeugen, dass wir eine funktionierende Anwendung haben, indem wir die URL http://localhost:3000/messages aufrufen. Aber so können wir natürlich nichts mit den Messages anfangen, eine Nachricht gehört ja zu einem Benutzer (wir wollen ja nicht alle Nachrichten sehen, sondern nur die eines Benutzers). Dass eine Nachricht zu einer Person gehört, haben wir bereits festgelegt. Die Angabe des Pseudo-Attributs person mit dem Typ references drückt die "N-Seite" einer 1:N Beziehnung aus. Die andere Seite (bei der Person) müssen wir noch definieren. Dazu erweitern wir das Model Person um eine Assoziation:

Eine entsprechende Ergänzung im Model der Klasse Message hat rails beim scaffolding automatisch erzeugt, dort als belongs_to :person.

Im Model haben wir jetzt die Beziehung zwischen Personen und Messages hergestellt, in der Anwendung (natürlich) noch nicht. Ein Benutzer muss seine Nachrichten lesen und neue verfassen können. Da diese Funktionalität aber im Allgemeinen anwendungsspezifisch ist, könnten wir hier mit automatisch generiertem Code sowieso nicht viel anfangen. rails erzeugt aus diesem Grund auch keinen solchen Code.

Das beudeutet aber nicht, das rails uns hier nicht die Arbeit (erheblich) erleichtert, bereits der Model-Code stellt eine ganze Menge Funktionalität zur Verfügung. Ein Person-Objekt hat jetzt beispielsweise eine Enumeration messages, die alle Nachrichten dieser Perosn enthät.

Die Verbindung zwischen den Personen und ihren Nachrichten

Zu jeder Person soll jetzt angezeigt werden, wieviele Nachrichten im Posteingang sind. Dazu müssen wir zunächst in der Datenbank nachschauen, wieviele Nachrichten zur aktuellen Person vorhanden sind und diese Zahl dann ausgeben. Nachgeschaut wird im Controller (people_controller.rb). Die Methode messages des Person-Objekts wurde von rails automatisch erzeugt, durch sie erhalten wir Zugriff auf alle Nachrichten dieser Person.


def show
	@person = Person.find(params[:id])
	@Nachrichten = @person.messages  
	

Ausgegeben wird im view (show.html.erb im Unterverzeichnis views/people).


<%=@Nachrichten.count> Nachrichten