I have a JRuby application that I am trying to create has_many through:
relationships for databases that live on two completely different servers. I understand that joins will not work across tables on different servers. What I would like is to simulate the joins so that a developer using the model doesn't have to be (as) aware of the cross-server join.
There are some additional complexities in this setup:
- The remote database is read-only
- The table names and primary keys in the remote database do not follow rails naming conventions. (The remote database is a Data Warehouse)
- I would like to be able to use the model as though a
has_and_belongs_to_many
was in it.
I've considered writing my own custom association, but that's a bit complex and I can't find any guides or really any starting points other then reading through the Rails code.
Is there an easy way to do this that I'm missing?
Is building a custom ActiveRecord association the best way to do this? and if so, where do I start?
Code similar to my setup:
config/database.yml
development:
adapter: postgresql
encoding: unicode
database: main
username: username
password: password
host: localhost
pool: 5
remote_development: # Read only
adapter: jdbcmssql
driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: 'jdbc:sqlserver://foo.com;databaseName=main'
username: username
password: password
app/models/account.rb
class Portfolio < ActiveRecord::Base
#has_and_belongs_to_many :dim_users, join_table: :accounts_dim_user
end
app/models/remote_model_base.rb
class RemoteModelBase
require "#{Rails.root}/lib/sqljdbc4.jar"
self.abstract_class = true
establish_connection "remote_#{Rails.env}".to_sym
after_initialize :readonly!
end
app/models/dim_user.rb
class DimUser < RemoteModelBase
self.table_name = 'DimUser'
self.primary_key = 'dwidDimUser'
#has_and_belongs_to_many :accounts, join_table: :accounts_dim_user
end
config/schema.rb
ActiveRecord::Schema.define(version: 20140925200106) do
create_table "accounts", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "accounts_dim_user", force: true, id: false do |t|
t.integer "dwidUser"
t.integer "account_id"
t.datetime "created_at"
t.datetime "updated_at"
end
# Defined in the remote database but it might look something like this
# create_table "DimUser" do |t|
# t.integer dwidUser
# # ...
# end