Ruby on Rails: ActiveRecord: Beziehungen
<< CRUD | Startseite/Inhaltsverzeichnis | Controller >>
In unserer Glossarverwaltung gibt es mehrere Kunden. Jeder hat sein eigenes Glossar mit vielen Glossareinträgen. Wie modellieren wir das? In einem Projekt gibt es mehrere Aufgaben. Jede Abteilung hat einen Abteilungsleiter. Ein Blogeintrag hat eine Überschrift und gehört zu vielen Kategorien. Offensichtlich sind Beziehungen zwischen Objekten etwas, was häufig vorkommt. Und natürlich könnten wir jede inividuell modellieren. Aber weil Beziehungen zwischen Objekten ein Standardproblem sind, bietet uns Rails Musterlösungen an, die wir ggf. anpassen können.
Die belongs_to Beziehung
[Bearbeiten]Fangen wir mit einer belongs-to Beziehung an. Betrachten wir als Beispiel die Beziehung zwischen einem Abteilungsleiter (manager) und einer Abteilung (department). Wir können behaupten, dass der manager zum department gehört. Das Modell dazu sieht dann so aus:
script/generate model department name:string description:text
script/generate model manager name:string department_id:integer
class Manager < ActiveRecord::Base
belongs_to :department
end
Die Zuordnung des manager zum department über die department_id ist eindeutig und über diese id kann man leicht das department zu einem manager herausfinden.
Die has_one Beziehung
[Bearbeiten]Mit einer has_one Beziehung können wir die Gegenrichtung modellieren. Das Datenbankmodel bleibt und wir schreiben:
class Department < ActiveRecord::Base
has_one :manager
end
Da wir im department die manager_id nicht kennen, müssen wir alle manager durchsuchen und ihre department_id checken, wenn wir den manager zu einem department herausfinden wollen.
Zusammen mit der belongs_to Beziehung haben wir jetzt eine 1:1 Beziehung modelliert, mit dem Fremdschlüssel department_id beim manager. Mit den belongs_to und has_one Beziehungen stellt uns Rails eine Reihe von Helper-methoden zur Verfügung:
test "we can create a department and manger without association" do
dep_edv = Department.create(:name => 'Department for EDV')
mgr_edv = Manager.create(:name => 'Egon Data')
assert_equal 'Department for EDV', dep_edv.name
assert_equal 'Egon Data', mgr_edv.name
assert_nil mgr_edv.department
assert_nil dep_edv.manager
end
test "we can associate department to manger (with manager-method)" do
dep_edv = Department.create(:name => 'Department for EDV')
mgr_edv = Manager.create(:name => 'Egon Data')
# in one direction we can navigate through the relationship
# this is because the (yet unsaved) manager already knows the department_id
mgr_edv.department = dep_edv
assert_equal dep_edv, mgr_edv.department
# for navigating in the other direction we have to save the ralationship data first
# i.e we need to save the manager
mgr_edv.save
# now we can navigate the relationship in the opposite direction too
# (this involves a seach for the manger with the appropriate id and thats why it has to be saved first)
assert_equal mgr_edv, dep_edv.manager
end
test "we can use build to create a department associaed to a manger" do
mgr_edv = Manager.create(:name => 'Egon Data')
dep_edv = mgr_edv.build_department(:name => 'Department for EDV')
assert_equal dep_edv, mgr_edv.department
mgr_edv.save
assert_equal mgr_edv, dep_edv.manager
end
# TODO build/create in die andere Richtung!
# TODO Unterschied zwischen build_other und create_other
Die has_many Beziehung
[Bearbeiten]Jetzt nehmen wir an, dass die Abteilungen nicht nur einen Abteilungsleiter sondern auch Angestellte (employees) haben. Das modellieren wir mit einer has_many Beziehung. Das macht die Zeile "has_many :employees". Die has_one Beziehung für den manager lassen wir wie sie ist. Die Abteilung soll ja weiterhin einen Abteilungsleiter haben.
script/generate model employee name:string department_id:integer
class Department < ActiveRecord::Base
has_one :manager
has_many :employees
end
Auch die belongs_to Beziehung in Gegenrichtung kennen wir schon.
class Employee < ActiveRecord::Base
belongs_to :department
end
Zusammen haben wir damit zusätzlich zur 1:1 Beziehung eine 1:n Beziehung modeliert und wieder stellt uns Rails eine Reihe von praktischen Methoden zur Verfügung. ..