Rails has a habit of lulling you into a false sense of security. The ease of use for common tasks makes you wonder why you’re wasting your time with Spring or JEE. Then you try to do something off the common path and watch Rails just shrug its shoulders and grin.
I was working on a community project recently and ran into the requirement to access some static data in another database. Multiple datasources, easy enough. Unfortunately, Rails expects you’ll be sticking with just one, and so I had to go hunting for a solution. Thankfully, I wasn’t the first to hit this and so many people had already done the hard work, leaving me with my piecing together the most elegant solution.
The first thing to do is define your datasource, presumably in database.yml.
legacy_datasource: adapter: mysql database: legacy_database timeout: 5000 encoding: utf8 host: localhost username: readonly enable_call: true password: readonly
You’ll then need to introduce a base class for the models which will use this datasource. It’ll need to be abstract, to avoid declaring any columns and establish a connection to the secondary source.
class LegacyObject < ActiveRecord::Base establish_connection :legacy_datasource self.abstract_class = true def self.columns() @columns ||= ; end def self.column(name, sql_type = nil, default = nil, null = true) columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) end end
Now build the model classes you require, making sure to extend from your new base class.
class AnObject < LegacyObject column :object_id, :integer # and so on... end
If you just require read-only access then you’re now done. If you require migration support then a bit more work is needed.
Create a new base class for the migrations that redefines the connection.
class LegacyMigration < ActiveRecord::Migration def self.connection LegacyDatasource.connection end end
Now, extend from the new base class and write your migration as normal.
class AMigration < LegacyMigration def self.up # ... end def self.down # ... end end
And you now have a complete solution. Despite the lack of official documentation, it’s surprisingly easy to do.