I am trying to build an app which will use one of latest Rails 6.1 features: multiple databases - you can read in sources at the bottom.
I would like to implement multitenancy by being able to switch between databases based on request domain.
Each club would have his own database, and one primary database would store app specific data like Users, Clubs.
I created two types of records: GlobalRecord using primary database and ShardRecord using horizontal shards databases.
And also tried to use around_action to select current club database.
# config/database.yml
default: &default
adapter: postgresql
encoding: unicode
development:
primary:
<<: *default
database: primary
migrations_paths: db/migrate
club_1:
<<: *default
database: club_1
migrations_paths: db/shard_migrate
club_2:
<<: *default
database: club_2
host: 1.1.1.1
username: deploy
password: pass
migrations_paths: db/shard_migrate
class Club < GlobalRecord; end
class GlobalRecord < ActiveRecord::Base
self.abstract_class = true
connects_to shards: {
club_1: { writing: :primary, reading: :primary },
club_2: { writing: :primary, reading: :primary }
}
end
class MemberRecord < ShardRecord; end
class ShardRecord < ActiveRecord::Base
self.abstract_class = true
connects_to shards: {
club_1: { writing: :club_1, reading: :club_1 },
club_2: { writing: :club_2, reading: :club_2 }
}
end
class ApplicationController < ActionController::API
before_action :set_club
around_action :connect_to_shard
private
def set_club
@club = SelectClubByDomain.new(request).slug
end
def connect_to_shard
ActiveRecord::Base.connected_to(role: :writing, shard: @club.slug) do
yield
end
end
end
I have few design questions/issues I would like to ask YOU about:
- I would like to set
GlobalRecordwithconnects_to database: { writing: :primary }but because I addedaround_actionI have to set it as above. Is it bad design? Can I refactor it so I could always call GlobalRecord withoutActiveRecord::Base.connected_to(role: :writing, shard: :club_1)block?
Tried to use ActiveRecord::Base.connected_to_many(GlobalRecord, ShardRecord, role: :writing, shard: @club_slug.to_sym) in around_action but on request(clubs#index => [Club.all]) I get an error:
ActiveRecord::ConnectionNotEstablished (No connection pool for 'GlobalRecord' found for the 'club_1' shard.)
- On production server on start I see this warning, how to fix it?
=> Run `bin/rails server --help` for more startup options
Failed to define attribute methods because of ActiveRecord::ConnectionNotEstablished: ActiveRecord::ConnectionNotEstablished
Sources: