ActiveRecord ohne Rails


ActiveRecord ist einer der Gründe, wieso Ruby on Rails so einfach und flexibel ist. Es ist ein sogenannter objektrelationaler Mapper. Damit lassen sich Daten aus einer Datenbank wie Objekte behandeln. Aber auch ohne Rails läßt sich ActiveRecord recht einfach einsetzen.

Als Beispiel habe ich hier 2 Tabellen in PostgreSQL, in denen ich eine Auswahl an Artikeln speichern möchte. Die Tabelle selections enthält den Namen der Auswahl von Artikeln und in selectionitems befinden sich die Artikel aus Auswahllisten. Die Tabellen haben folgendes Schema:

CREATE TABLE selections (
  id                SERIAL PRIMARY KEY,
  name              VARCHAR(30)
);

CREATE TABLE selectionitems (
  id                SERIAL PRIMARY KEY,
  part_id           INTEGER,
  selection_id      INTEGER,
  sort_order        INTEGER
);

Die beiden Tabellen habe ich mit Testdaten gefüllt.

artikel=# select * from selections;
 id | name
----+------
  1 | foo
(1 row)

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
(3 rows)

Die Namen der Tabellen und der Felder sind schon ziemlich Rails-like, so daß in den folgenden Beispielen sehr viele Einstellungen überflüssig sind. Aber ich habe sie hier eingetragen, um zu zeigen, wie man mit beliebigen Tabellen arbeiten könnte.

Mit ActiveRecord verpacke ich nun die beiden Tabellen. Falls es beim require bzw. require_gem zu Fehlern kommen sollte, sind vermutlich die Ruby Gems bzw. das ActiveRecord-Gem nicht installiert. (Genaueres ist auf der Ruby Gems Website beschrieben)

require 'rubygems'
require_gem 'activerecord'

ActiveRecord::Base.establish_connection(
  :adapter    => "postgresql",
  :host       => "localhost",
  :database   => "artikel",
  :username   => "dbuser",
  :password   => "kryptisches_passwort"
)

class Selection < ActiveRecord::Base
  set_table_name "selections"
  set_primary_key "id"
  has_many  :items,
            :class_name => "SelectionItem",
            :foreign_key => "selection_id",
            :order => "sort_order"
end

class SelectionItem < ActiveRecord::Base
  set_table_name "selectionitems"
  set_primary_key "id"
  belongs_to  :selection,
              :class_name => "Selection",
              :foreign_key => "selection_id"
end

Das war der ganze Code, um die beiden Tabellen in Objekte zu verpacken. Was genau steht nun da oben? ActiveRecord::Base.establish_connection() dürfte eigentlich selbsterklärend sein. Interessant wird es bei der Klasse Selections. Ich sage der Klasse mit set_table_name auf welcher Tabelle aus der Datenbank sie basieren soll und mit set_primary_key wie die Spalte mit dem Primärschlüssel heißt. (ActiveRecord hat hier einige Automatismen um vom Namen der Klasse auf den Tabellennamen zu schließen, die ich jedoch bewußt nicht benutzt habe.) Mit has_many habe ich bestimmt, daß jede Instanz der Klasse Selections mehrere Instanzen der Klasse SelectionItem enthalten kann. Die Zuordnung dieser items zu einer Selection geschieht anhand der selection_id aus SelectionItem. Ähnlich habe ich auch in SelectionItem bestimmt, auf welcher Tabelle es basieren soll. Und umgekehrt zu has_many habe ich hier mit belongs_to festgelegt, daß eine Instanz von SelectionItem zu einer bestimmten Selection gehört.

Wie benutze ich das nun? Ich ich suche erstmal die in den Tabellen gespeicherte Auswahl.

irb(main):028:0> foo = Selection.find_by_name("foo")
=> #"foo", "id"=>"1"}>

Wer Ruby on Rails schon gesehen hat, wird das wiedererkennen. Und all die anderen halten es für Magie :) Hier ist die erste Auswahl mit den Namen foo. Diese Auswahl enthält nun einige Artikel. Mal schauen, was ich da habe.

irb(main):029:0> foo.items.count
=> 3
irb(main):030:0> foo.items.each { |bar| puts bar.part_id }
42
123
23

Da ist meine Auswahl. Jetzt will ich ein weiteren Artikel zu dieser Auswahl hinzufügen.

irb(main):031:0> foo.items.create(:part_id => 451, :sort_order => 4)
=> #>, @attributes={"part_id"=>451, "sort_order"=>4, "selection_id"=>1, "id"=>4}>
irb(main):032:0> foo.items.count
=> 4
irb(main):033:0> foo.items.each { |bar| puts bar.part_id }
42
123
23
451

Das war aber noch nicht alles. Ich möchte in meiner Auswahl den zweiten Artikel herausfinden.

irb(main):035:0> foo.items.find_by_sort_order(2).part_id
=> 123

Ich kann diese Auswahl aber auch wie ein Array betrachten. (Achtung, Arrays fangen bei 0 an!)

irb(main):038:0> foo.items[1].part_id
=> 123

Besondere Erwähnung verdient die Suchfunktion. Ich sage nur find_by_feldname, und es wird anhand dieses Feldes in der Tabelle gesucht. ActiveRecord erzeugt also automagisch für alle Tabellenfelder find-Methoden. Das geht sogar so weit, daß man auch mehrere Suchkriterien kombinieren kann.

irb(main):041:0> foo.items.find_by_part_id_and_sort_order(123,2)
=> #"123", "sort_order"=>"2", "selection_id"=>"1", "id"=>"3"}>

Wenn ActiveRecord nichts findet, gibt es einfach nil zurück.

irb(main):040:0> foo.items.find_by_part_id_and_sort_order(123,3)
=> nil

Und für all diejenigen, die ihren Augen noch nicht trauen, hier noch ein letzter Blick in die Datenbank. Ich zeige hier nur die Tabelle selectionitems, da ich nur darin was geändert habe.

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
  4 |     451 |            1 |          4
(4 rows)

Wer sich nun mit den Details von ActiveRecord auseinander setzen möchte, sollte in die Ruby on Rails-Dokumentation schauen.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.