PostgreSQL bietet, wie einige andere Datenbanken auch, die Möglichkeit Schemata zu definieren um Namensräume für Tabellen und andere Datenbankobjekte anzulegen. Rails’ Postgres Adapter kann mit Schemata umgehen und mit ein paar Tricks hat man eine Menge interessanter Anwendungsmöglichkeiten.
Am Anfang war die Konfiguration. Diese erfolgt wie üblich in der config/database.yml. Der Postgres Adapter kennt das Schlüsselwort schema_search_path. Wenn man z.B.
schema_search_path: myschema,otherschema,public
angibt, werden Datebankobjekte zunächst in myschema, dann in otherschema und schließlich in public gesucht.
Ein Anwendungsbeispiel wären z.B. temporäre Tabellen, die man während der Laufzeit erzeugen und mit einem ‘DROP SCHEMA xyz’ wieder löschen kann.
Will man hingegen eine ganze Railsanwendung in einem Schema laufen lassen, stößt man unweigerlich auf ein Problem mit den Tests. Bei Tests wird ein “DROP testdatenbank” durchgeführt und das nimmt natürlich nicht nur das verwendete Schema mit ins Datennirvana.
Deshalb muß der Task ‘create_database’ und die Methode ‘drop_database’ ein wenig gepatcht werden. Man erstellt also in ‘/lib/tasks/core.rake’ (oder wie man es auch immer nennen mag) eine Date folgenden Inhalts:
namespace :db do namespace :create do def create_database(config) #ensure the database exists: begin ccopy=config.dup.merge('schema_search_path' => 'public') ActiveRecord::Base.establish_connection(ccopy) ActiveRecord::Base.connection rescue @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8' begin ccopy=config.dup.merge('database' => 'postgres', 'schema_search_path' => 'public') ActiveRecord::Base.establish_connection(ccopy) ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding)) rescue $stderr.puts $!, *($!.backtrace) $stderr.puts "Couldn't create database for #{config.inspect}" end else $stderr.puts "#{config['database']} already exists" end #ensure the schema exists: if schema_name=config['working_schema'] begin ActiveRecord::Base.establish_connection(config) ActiveRecord::Base.connection rescue ActiveRecord::StatementInvalid => e puts e.class.ancestors.inspect begin ccopy=config.dup.merge('schema_search_path' => 'public') ActiveRecord::Base.establish_connection(ccopy) ActiveRecord::Base.connection.execute("CREATE SCHEMA \"#{schema_name}\"") ActiveRecord::Base.establish_connection(config) rescue $stderr.puts $!, *($!.backtrace) $stderr.puts "Couldn't create database for #{config.inspect}" end #some error end end #schema end end end def drop_database(config) ActiveRecord::Base.establish_connection(config. merge('database' => 'postgres', 'schema_search_path' => 'public')) if schema_name=config['working_schema'] ActiveRecord::Base.connection.execute "DROP SCHEMA IF EXISTS \"#{schema_name}\" CASCADE" else ActiveRecord::Base.connection.drop_database config['database'] end end
Die config/database.yml könnte wie folgt aussehen:
test: adapter: postgresql database: development schema_search_path: test,base_data,public working_schema: test host: myhost username: username password: password
Durch diesen Patch kann man ein “working_schema” wie eine richtige Datenbank verwenden. Wozu das gut ist?
- Mehrere Applikationen können sich eine Datenbank teilen.
- Die Applikationen können sich Basisdaten (User, Geolocations, …) und andere Datenbankobjekte teilen.
- Man benötigt keine DROP/CREATE DATABASE Privilegien.
- Im Gegensatz zu Datenbanken können Abfragen schemata-übergreifend formuliert werden.
Lasst euch was einfallen und viel Spaß beim einem interessanten Setup (und das bestimmt nicht nach Schema F).
Schlagworte: datenbanken, postgresql

