-
-
Save AlexKalinin/35036e86a065e6ce4b8531f4c9d1a9e5 to your computer and use it in GitHub Desktop.
Simple example showing how to monkey patch ActiveRecord to allow database switching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# got from here: https://stackoverflow.com/a/43819672 | |
# Define some required dependencies | |
require "bundler/inline" | |
gemfile(false) do | |
source "https://rubygems.org" | |
gem "activerecord", "~> 4.2.8" | |
gem "sqlite3" | |
end | |
require "active_record" | |
class User < ActiveRecord::Base | |
end | |
DatabaseModel = Struct.new(:name) do | |
def superclass | |
ActiveRecord::Base | |
end | |
end | |
# Setup database connections and create databases if not present | |
connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new | |
resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new({ | |
"users_shard_1" => { adapter: "sqlite3", database: "users_shard_1.sqlite3" }, | |
"users_shard_2" => { adapter: "sqlite3", database: "users_shard_2.sqlite3" } | |
}) | |
databases = %w{users_shard_1 users_shard_2} | |
databases.each do |database| | |
filename = "#{database}.sqlite3" | |
ActiveRecord::Base.establish_connection({ | |
adapter: "sqlite3", | |
database: filename | |
}) | |
spec = resolver.spec(database.to_sym) | |
connection_handler.establish_connection(DatabaseModel.new(database), spec) | |
next if File.exists?(filename) | |
ActiveRecord::Schema.define(version: 1) do | |
create_table :users do |t| | |
t.string :name | |
t.string :email | |
end | |
end | |
end | |
# Create custom connection handler | |
class ShardHandler | |
def initialize(original_handler) | |
@original_handler = original_handler | |
end | |
def use_database(name) | |
@model= DatabaseModel.new(name) | |
end | |
def retrieve_connection_pool(klass) | |
@original_handler.retrieve_connection_pool(@model) | |
end | |
def retrieve_connection(klass) | |
pool = retrieve_connection_pool(klass) | |
raise ConnectionNotEstablished, "No connection pool for #{klass}" unless pool | |
conn = pool.connection | |
raise ConnectionNotEstablished, "No connection for #{klass} in connection pool" unless conn | |
puts "Using database \"#{conn.instance_variable_get("@config")[:database]}\" (##{conn.object_id})" | |
conn | |
end | |
end | |
User.connection_handler = ShardHandler.new(connection_handler) | |
User.connection_handler.use_database("users_shard_1") | |
User.create(name: "John Doe", email: "[email protected]") | |
puts User.count | |
User.connection_handler.use_database("users_shard_2") | |
User.create(name: "Jane Doe", email: "[email protected]") | |
puts User.count | |
User.connection_handler.use_database("users_shard_1") | |
puts User.count |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment