我正在尝试构建一个应用程序,该应用程序将使用Rails 6.1
的最新功能之一:multiple databases
-您可以在底部读取源代码。
我想通过能够在基于请求域的数据库之间切换来实现多租户。
每个俱乐部都有自己的数据库,一个主数据库将存储特定于应用程序的数据,如用户、俱乐部。
我创建了两种类型的记录:GlobalRecord
使用primary
数据库,ShardRecord
使用水平碎片数据库。
并尝试使用around_action
来选择当前的俱乐部数据库。
# 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
我有几个设计问题想问你:
- 我想用
connects_to database: { writing: :primary }
设置GlobalRecord
,但因为我添加了around_action
我必须如上所述设置。设计不好吗?我可以重构它,这样我就可以在没有ActiveRecord::Base.connected_to(role: :writing, shard: :club_1)
块的情况下始终调用GlobalRecord吗
尝试在around_action
中使用ActiveRecord::Base.connected_to_many(GlobalRecord, ShardRecord, role: :writing, shard: @club_slug.to_sym)
,但应请求(clubs#index => [Club.all]
(,我收到错误:
ActiveRecord::ConnectionNotEstablished (No connection pool for 'GlobalRecord' found for the 'club_1' shard.)
- 在生产服务器上启动时,我看到了此警告,如何修复
=> Run `bin/rails server --help` for more startup options
Failed to define attribute methods because of ActiveRecord::ConnectionNotEstablished: ActiveRecord::ConnectionNotEstablished
来源:
- https://guides.rubyonrails.org/active_record_multiple_databases.html
- https://www.freshworks.com/horizontal-sharding-in-a-multi-tenant-app-with-rails-61-blog/
- https://api.rubyonrails.org/classes/ActiveRecord/ConnectionHandling.html#method-i-connected_to_many
一般来说,使用around过滤器切换连接是完全可以的,我们在以前的公司已经做了很多年了(甚至在Rails6之前(。
顺便问一句:你看到导游提到你发布的异常了吗?
请注意,具有角色的connected_to将查找现有连接并使用连接规范名称进行切换。这意味着,如果您传递一个未知的角色,如connected_to(角色::不存在(,您将得到一个错误,上面写着ActiveRecord::ConnectionNotEstablished(对于"不存在"的角色,找不到"ActiveRecord::Base"的连接池。(
https://guides.rubyonrails.org/active_record_multiple_databases.html#using-手动连接切换