SchemaQualifiedTables

Bcdatabase::ActiveRecord::SchemaQualifiedTables is a mix-in for ActiveRecord 2.3.x and 3.0+. It makes it easier to use AR in an application which contains models which map to tables in different schemas.

For example

Say you have an application using a legacy schema that has models like this:

# Rails 2.3, 3.0 and 3.1
class Surgery < ActiveRecord::Base
  belongs_to :surgeon, :class_name => "Person", :foreign_key => "surgeon_id"
  set_table_name "t_surgeries"
end

class Person < ActiveRecord::Base
  set_table_name "hr.t_personnel"
end

# Rails 3.2+
class Surgery < ActiveRecord::Base
  belongs_to :surgeon, :class_name => "Person", :foreign_key => "surgeon_id"
  self.table_name = "t_surgeries"
end

class Person < ActiveRecord::Base
  self.table_name = "hr.t_personnel"
end

These models map to tables in two schemas: the default schema, which contains t_surgeries; and the schema hr, which contains t_personnel.

Contention

Being explicit about the schema name works for production, but what about development? You'll need separate database instances for development deployment and for test. Depending on what database you're using, this can be more or less fun (I'm looking at you, Oracle).

Also consider continuous integration: if you have several applications in CI which all refer to the hr schema, their test data sets will stomp all over each other if you try to run them in parallel.

Solution

SchemaQualifiedTables solves this problem by letting you configure a logical schema name for your models which is resolved into the actual schema name based on runtime configuration. In this case, you'd re-write Person like so:

# Rails 2.3, 3.0 and 3.1
class Person < ActiveRecord::Base
  set_schema :hr
  set_table_name :t_personnel
end

# Rails 3.2+
class Person < ActiveRecord::Base
  self.schema = :hr
  self.table_name = :t_personnel
end

(Please note: The deprecated-in-Rails-3.2 syntax set_table_name and set_sequence_name does not work with schema qualified tables in Rails 3.2.)

Then, if you need to override the actual schema name in some environments, configure ActiveRecord::Base.schemas:

# in test.rb

# For Rails 2.3
config.after_initialize do
  ActiveRecord::Base.schemas = { :hr => 'hr_test' }
end

# For Rails 3.x
MyApp::Application.configure do
  ...
  # _not_ within an after_initialize block
  ActiveRecord::Base.schemas = { :hr => 'hr_test' }
  ...
end

This way in the test environment, AR will map Person to hr_test.t_personnel. In any environment where you don't provide an explicit override, the logical schema name will be used as the actual schema name — i.e., in development and production, AR will map Person to hr.t_personnel.

Using

Install the gem:

$ gem install schema_qualified_tables

If you're using Rails 2.3, configure it in environment.rb:

config.gem 'schema_qualified_tables', :version => '>= 1.0.0'

If you're using Bundler (e.g., with Rails 3), add it to your Gemfile:

gem 'schema_qualified_tables', '~> 1.0.0'

Otherwise, just require 'schema_qualified_tables' sometime during initialization (before your models are loaded).

Problems?

Report bugs or request features on the project's github issue tracker.

Send any other questions or feedback to Rhett Sutphin ([email protected]).

Development

This library uses bundler to provide an isolated gem environment for its tests. Use bundle update before attempting to run the tests.

In order to test all the features of schema_qualified_tables, ActiveRecord must be given a connection to a database on an RDBMS that supports sequences. The test harness uses Bcdatabase to acquire the credentials for the test database. By default, it looks for the Bcdatabase group :local_postgresql and the configuration :schema_qualified_tables_test. You can override these by setting environment variables when you run the tests, e.g.:

SQT_DB_GROUP=local_oracle
SQT_DB_ENTRY=sqt_tester

The test harness supports using PostgreSQL or Oracle. Adding support for another database should be as easy as adding its adapter (or its adapter's dependencies, if it has an adapter built into AR) to a group the Gemfile and running bundle update. The test suite can only be run without failures on a database that supports sequences.

(N.b.: since it's relatively difficult to install the supporting library for Oracle, it isn't included in the Gemfile by default. If you want to test against Oracle, set SQT_ORACLE=true in your environment before running bundle update and the tests.)

On JRuby

If you want to run the tests on JRuby using a database whose JDBC drivers are not available as a gem (i.e., Oracle), ensure that the JDBC driver is on JRuby's classpath before running the tests. The easiest way to do that is by setting the CLASSPATH environment variable.

Credits

SchemaQualifiedTables was developed at the Northwestern University Biomedical Informatics Center.

Copyright (c) 2009 Rhett Sutphin and Peter Nyberg. See LICENSE for details.