Rails中的多个数据库

时间:2009-12-01 12:19:21

标签: ruby-on-rails database activerecord

可以这样做吗?在单个应用程序中,使用SQLite管理许多项目。 我想要的是为我的应用程序管理的每个项目都有一个不同的数据库..所以同一结构化数据库的多个副本,但其中包含不同的数据。我将根据URI上的params选择使用哪个副本。

这是为1.安全性做的..我是这种编程的新手,我不希望它发生在某个原因上工作项目时另一个被破坏了.2。易于备份和旧项目的存档

9 个答案:

答案 0 :(得分:39)

默认情况下,Rails不是为多数据库架构而设计的,在大多数情况下,它根本没有意义。 但是,您可以使用不同的数据库和连接。

以下是一些参考资料:

答案 1 :(得分:27)

如果您能够控制和配置每个Rails实例,并且由于它们处于待机状态而您可以负担浪费资源,请省去一些麻烦,只需更改database.yml即可修改每个实例上使用的数据库连接。如果你担心性能,这种方法不会削减它。

对于仅在一个数据库上绑定到单个唯一表的模型,可以在模型中调用establish_connection:

establish_connection "database_name_#{RAILS_ENV}"

如下所述:http://apidock.com/rails/ActiveRecord/Base/establish_connection/class

您将使用来自一个数据库的表和其他不同模型的表使用其他数据库中的表。

如果您有相同的表,在不同的数据库上共用,并由单个模型共享,ActiveRecord将无法帮助您。早在2009年,我就使用Rails 2.3.8对我正在开发的项目提出了这个要求。我有一个每个客户的数据库,我用他们的ID命名数据库。所以我创建了一个方法来更改ApplicationController中的连接:

def change_database database_id = params[:company_id]
    return if database_id.blank?

    configuration = ActiveRecord::Base.connection.instance_eval { @config }.clone
    configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"

    MultipleDatabaseModel.establish_connection configuration
end

将该方法作为 before_filter 添加到所有控制器:

before_filter :change_database

因此,对于每个控制器的每个动作,当定义和设置params [:company_id]时,它会将数据库更改为正确的数据库。

为了处理迁移我扩展了ActiveRecord :: Migration,其方法是查找所有客户并使用每个ID迭代一个块:

class ActiveRecord::Migration
    def self.using_databases *args
        configuration = ActiveRecord::Base.connection.instance_eval { @config }
        former_database = configuration[:database]

        companies = args.blank? ? Company.all : Company.find(args)

        companies.each do |company|
            configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
            ActiveRecord::Base.establish_connection configuration

            yield self
        end

        configuration[:database] = former_database
        ActiveRecord::Base.establish_connection configuration
    end
end

请注意,通过执行此操作,您无法在两个不同数据库的同一操作中进行查询。您可以再次调用 change_database 但是当您尝试使用执行查询的方法时,从不再链接到正确数据库的对象开始,它会变得很糟糕。此外,显然您将无法连接属于不同数据库的表。

为了正确处理这个问题,应该大大扩展ActiveRecord。现在应该有一个插件来帮助您解决这个问题。一个快速的研究给了我这个:

DB-Charmer:http://kovyrin.github.com/db-charmer/

我愿意尝试一下。让我知道什么对你有用。

答案 2 :(得分:12)

我通过使用其他数据库

将其添加到我的模型顶部来解决这个问题
class Customer < ActiveRecord::Base
  ENV["RAILS_ENV"] == "development" ? host = 'devhost' : host = 'prodhost'

  self.establish_connection(
      :adapter  => "mysql",
      :host     => "localhost",
      :username => "myuser",
      :password => "mypass",
      :database => "somedatabase"
    )

答案 3 :(得分:4)

您还应该查看名为DB Charmer的项目: http://kovyrin.net/2009/11/03/db-charmer-activerecord-connection-magic-plugin/

  

DbCharmer是一个简单但功能强大的ActiveRecord插件,可以做一些事情:

     
      
  1. 允许您轻松管理AR模型的连接(switch_connection_to方法)
  2.   
  3. 允许您将AR模型的默认连接切换到单独的服务器/数据库
  4.   
  5. 允许您轻松选择查询的位置(on_*方法系列)
  6.   
  7. 允许您自动向您的从服务器发送读取查询,而主服务器将处理所有更新。
  8.   
  9. 将多个数据库迁移添加到ActiveRecord
  10.   

答案 4 :(得分:2)

值得注意的是,在所有这些解决方案中,您需要记住关闭自定义数据库连接。 用完连接,否则会看到奇怪的请求超时问题。

一个简单的解决方案是clear_active_connections!在你的控制器的after_filter中。

after_filter :close_custom_db_connection

def close_custom_db_connection
  MyModelWithACustomDBConnection.clear_active_connections!
end

答案 5 :(得分:0)

你的config / database.yml中的

做了类似这样的事情

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5

development:
  <<: *default
  database: mysite_development

test:
  <<: *default
  database: mysite_test

production:
  <<: *default
  host: 10.0.1.55
  database: mysite_production
  username: postgres_user
  password: <%= ENV['DATABASE_PASSWORD'] %>

db2_development:
  <<: *default
  database: db2_development

db2_test:
  <<: *default
  database: db2_test

db2_production:
  <<: *default
  host: 10.0.1.55
  database: db2_production
  username: postgres_user
  password: <%= ENV['DATABASE_PASSWORD'] %>

然后在您的模型中,您可以使用

引用db2
class Customers < ActiveRecord::Base
  establish_connection "db2_#{Rails.env}".to_sym
end

答案 6 :(得分:0)

您在问题中描述的是多租户(结构相同的数据库,每个数据库中包含不同的数据)。 Apartment gem对此非常有用。

对于Rails中多个数据库的一般问题:ActiveRecord支持多个数据库,但Rails不提供管理它们的方法。我最近创建了Multiverse gem来解决这个问题。

答案 7 :(得分:0)

到目前为止,我发现的最佳解决方案是:

我们可以采用3种数据库架构。

  • 单个租户的单个数据库
  • 每个租户的独立架构
  • 租户共享架构

注意:它们有某些优缺点,取决于您的用例。

我是从Blog那里得到的!对我来说很有帮助。

您可以将Apartment宝石用于轨道

您可以在Gorails for apartment上观看视频参考

答案 8 :(得分:0)

从 Rails 6 开始,支持多个数据库:https://guides.rubyonrails.org/active_record_multiple_databases.html#generators-and-migrations

对于迟到且显而易见的答案感到抱歉,但认为它是可行的,因为它现在得到支持。