In diesem Abschnitt gehe ich exemplarisch auf Themen und Fragen ein,
die im täglichen Arbeiten wichtig sind, aber in der Gesamtheit zu komplex
für ein Anfängerbuch. Es gibt kochrezeptartig Lösungen für konkrete
ActiveRecord-Probleme.
Callbacks sind definierte Programmier-Einstiegspunkte (Hooks) im
Leben eines ActiveRecord-Objektes. Eine Aufstellung aller Callbacks finden
Sie auf
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
.
Hier sind die am häufigsten verwendeten:
before_validation
Wird vor der Validierung ausgeführt.
after_validation
Wird nach der Validierung ausgeführt.
before_save
Wird vor jedem Abspeichern ausgeführt.
before_create
Wird vor dem ersten Abspeichern ausgeführt.
after_save
Wird nach jedem Abspeichern ausgeführt.
after_create
Wird nach dem ersten Abspeichern ausgeführt.
Ein Callback wird immer im Model ausgeführt. Nehmen wir einmal an,
dass Sie E-Mail-Adresse in einem
User
-Model immer
in Kleinbuchstaben speichern wollen, aber dem Benutzer des Webinterfaces
die Möglichkeit geben möchten, auch Großbuchstaben einzugeben. Dann
könnten Sie mit einem
before_save
-Callback das
Attribute
email
mit der Methode
downcase
in Kleinbuchstaben umwandeln. Das Model
sähe dann so aus:
class User < ActiveRecord::Base
attr_accessible :email, :name
validates :name,
:presence => true
validates :email,
:presence => true,
:format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
before_save :downcase_email
private
def downcase_email
self.email = self.email.downcase
end
end
Probieren wir einmal in der Console aus, ob es auch so funktioniert,
wie wir es uns vorstellen:
MacBook:webshop xyz$ rails console
Loading development environment (Rails 3.2.3)
1.9.3p194 :001 > User.create(name: 'Wintermeyer', email: 'Stefan.Wintermeyer@amooma.de')
(0.1ms) begin transaction
SQL (5.9ms) INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Wed, 30 May 2012 18:20:21 UTC +00:00], ["email", "stefan.wintermeyer@amooma.de"], ["name", "Wintermeyer"], ["updated_at", Wed, 30 May 2012 18:20:21 UTC +00:00]]
(2.8ms) commit transaction
=> #<User id: 1, name: "Wintermeyer", email: "stefan.wintermeyer@amooma.de", created_at: "2012-05-30 18:20:21", updated_at: "2012-05-30 18:20:21">
1.9.3p194 :002 > exit
MacBook:webshop xyz$
Obwohl die E-Mail-Adresse mit einem großen 'S' und 'W' angegeben
wurde, hat ActiveRecord automatisch innerhalb des
before_save
-Callbacks alle Buchstaben in
Kleinbuchstaben umgewandelt.
In
Kapitel 9, Action Mailer finden Sie ein Beispiel für das
gleiche Model, bei dem mit einem
after_create
-Callback automatisch eine E-Mail an
einen neu angelegten User verschickt wird. In
„Default-Werte“ finden Sie ein Beispiel, wie mit einem
after_initialize
-Callback ein Default-Wert für
ein neues Objekt definiert wird.
Wenn Sie bei einem ActiveRecord-Objekt bestimmte Default-Werte
brauchen, so können Sie das am einfachsten mit dem
after_initialize
-Callback realisieren. Diese
Methode wird von ActiveRecord beim Erstellen eines neuen Objektes
aufgerufen. Angenommen, wir haben eine Model-Bestellung
(Order
) und eine Mindestbestellmenge liegt immer
bei 1, dann können wir beim Erstellen eines neuen Datensatzes ja direkt 1
als Default-Wert eintragen.
Setzen wir das Beispiel kurz auf:
MacBook:~ xyz$ rails new shop
[...]
MacBook:~ xyz$ cd shop
MacBook:shop xyz$ rails generate model order product_id:integer quantity:integer
[...]
MacBook:shop xyz$ rake db:migrate
[...]
MacBook:shop xyz$
Wir schreiben in die Datei
app/models/order.rb
einen
after_initialize
-Callback:
class Order < ActiveRecord::Base
attr_accessible :product_id, :quantity
after_initialize :set_defaults
private
def set_defaults
self.quantity ||= 1
end
end
Und jetzt probieren wir in der Console aus, ob ein neues
Order-Objekt automatisch die Menge 1 enthält:
MacBook:shop xyz$ rails console
Loading development environment (Rails 3.2.3)
1.9.3p194 :001 > order = Order.new
=> #<Order id: nil, product_id: nil, quantity: 1, created_at: nil, updated_at: nil>
1.9.3p194 :002 > exit
MacBook:shop xyz$
Funktioniert wie gewünscht.
Anmerkung
Einige Leser werden sich fragen, warum wir nicht in der Migration
einen Default in der Datenbank gesetzt haben. Wie so oft, gibt es auch
für dieses Problem mehrere Lösungsmöglichkeiten.