Rails7:切换到不同的数据库

Rails 7: switch to different databases

我试图在我的脚本中连接到不同的数据库,但我得到 ActiveRecord::ConnectionNotEstablished: No connection pool for 'ActiveRecord::Base' found for the 'main' shard.

来自database.yml的相关代码如下

test:
  primary:
    adapter: postgresql
    database: test
    database: "<%= ENV['DATABASE_NAME'] %>"
    username: "<%= ENV['DATABASE_USERNAME'] %>"
    password: "<%= ENV['DATABASE_PASSWORD'] %>"
    host: "<%= ENV['DATABASE_HOST'] %>"
  main:
    adapter: postgresql
    username: postgres
    database: "<%= ENV['API_MAIN_DATABASE_NAME'] %>"
    password: "<%= ENV['API_DATABASE_PASSWORD'] %>"
    host: "<%= ENV['API_DATABASE_HOST'] %>"
    database_tasks: false
  prediction:
    adapter: postgresql
    username: postgres
    database: "<%= ENV['API_PREDICTION_DATABASE_NAME'] %>"
    password: "<%= ENV['API_DATABASE_PASSWORD'] %>"
    host: "<%= ENV['API_DATABASE_HOST'] %>"
    database_tasks: false
  onshore:
    adapter: postgresql
    username: postgres
    database: "<%= ENV['API_US_ONSHORE_DATABASE_NAME'] %>"
    password: "<%= ENV['API_DATABASE_PASSWORD'] %>"
    host: "<%= ENV['API_DATABASE_HOST'] %>"
    database_tasks: false

我有 3 个模型连接到 mainpredictiononshore 数据库,如下所示

class ExternalRecord < ApplicationRecord
  self.abstract_class = true
  connects_to shards: { writing: :primary, reading: :main }
end

class ExternalRecordPrediction < ApplicationRecord
  self.abstract_class = true
  connects_to shards: { writing: :primary, reading: :prediction }
end

class ExternalRecordOnshore < ApplicationRecord
  self.abstract_class = true
  connects_to shards: { writing: :primary, reading: :onshore }
end

我正在尝试通过在循环中连接到这三个不同的数据库来进行一些处理,如下所示

     ActiveRecord::Base.connected_to(role: :reading, shard: :main) do
     results = ActiveRecord::Base.connection.execute(query_here)
     #process results

但是我得到一个错误ActiveRecord::ConnectionNotEstablished: No connection pool for 'ActiveRecord::Base' found for the 'main' shard.

如何在脚本中切换到不同的数据库。

我正在使用 Rails 7

我之前使用 Rails 5 并使用 ar-octopus 来实现这一点。

ActiveRecord::Base 与您的 ApplicationRecord class 或设置了 primary_abstract_class 的其他 class 共享连接。你必须在那里设置connects_to

class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class # <= there can only be one in your app

  connects_to database: { writing: :primary, reading: :main }
end
# if you are in a console make sure ApplicationRecord class is loaded
ApplicationRecord

ActiveRecord::Base.connected_to(role: :reading) do
  # ActiveRecord::Base.current_role                     # => :reading
  # ActiveRecord::Base.current_shard                    # => :default
  #   :default is configuration named 'primary' or the first entry if 'primary' is not found
  # ActiveRecord::Base.connection.execute("INSERT ...") # => ActiveRecord::ReadOnlyError
  
  ActiveRecord::Base.connection.execute("SELECT ...")   # ok
end

有碎片

class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class

  connects_to shards: {
    one: { writing: :primary, reading: :main },
    # two: ...
  }
end
# if you are in a console make sure ApplicationRecord class is loaded
ApplicationRecord

ActiveRecord::Base.connected_to(role: :reading, shard: :one) do
  # ActiveRecord::Base.current_role                     # => :reading
  # ActiveRecord::Base.current_shard                    # => :one
  # ActiveRecord::Base.connection.execute("INSERT ...") # => ActiveRecord::ReadOnlyError
  
  ActiveRecord::Base.connection.execute("SELECT ...")   # ok
end

参考: rails v7.0.2.3 ruby v3.1.1

您也可以只强制连接。但我不知道这有多安全,我不会在主应用程序中使用它。

ActiveRecord::Base.establish_connection(:prediction)
# do it here
ActiveRecord::Base.establish_connection # back to default just in case