【问题标题】:ActiveRecord talk to two databases?ActiveRecord 与两个数据库对话?
【发布时间】:2010-08-31 13:32:43
【问题描述】:

我们最近改造了一个项目,并希望将我们所有的旧数据引入新系统。问题是架构略有不同,因此无法直接导入 SQL。由于一些非规范化和数据库更改,我们需要在准备好导入数据之前对数据进行一些处理。我希望有这样的东西:

OldUser.all.each do |ou|
  NewUser.create({
    :first_name   => ou.first_name
    :last_name    => ou.last_name
    :login        => ou.login
    :company_name => ou.company.name
  })
end

在上面的示例中,OldUser 正在从旧数据库中读取数据,而 NewUser 正在处理新数据库。我需要两组模型(新的和旧的)来保留它们的关联,以正确地对一些数据进行非规范化。

是否有任何项目/库可以帮助我做到这一点?

【问题讨论】:

    标签: ruby-on-rails ruby database activerecord


    【解决方案1】:

    您应该在模型或 database.yml 中简单地指定您的连接选项。我们先走第一条路线:

    # This is the new users table - connects to development/test/production
    # DB from database.yml
    class User < ActiveRecord::Base
    end
    
    class OldUser < ActiveRecord::Base
      establish_connection :adapter  => "postgresql",
                           :database => "legacy_users",
                           :username => "whatever",
                           :password => "something"
      set_table_name "u_users" # Whatever you require
      belongs_to :company, :class_name => "OldCompany", :foreign_key => "fk_company_id"
    end
    
    class OldCompany < ActiveRecord::Base
      establish_connection :adapter  => "postgresql",
                           :database => "legacy_users",
                           :username => "whatever",
                           :password => "something"
      set_table_name "u_company" # Whatever you require
      has_many :users, :class_name => "OldUser", :foreign_key => "fk_company_id"
    end
    

    从常规代码中,您可以像以前一样使用模型:

    OldUser.find_each do |ouser|
      User.create!(:username => ouser.username, :company_name => ouser.company.name)
    end
    

    ActiveRecord 将为您处理所有细节。

    现在,如果你和我一样,你不喜欢在你的模型中加入如此详细的信息——用户名、密码等。简单——将该配置移动到 database.yml 并使用正确的建立连接语法进行连接:

    # database.yml
    development:
      adapter: postgresql
      # go on as usual, for all 3 envs
    
    legacy_users_development:
      adapter:  postgresql
      database: legacy_users
      username: whatever
      password: something
    

    注意命名约定 - legacy_users_#{Rails.env} 是我的目标,这里是如何做到的:

    class OldUser < ActiveRecord::Base
      establish_connection "legacy_users_#{Rails.env}"
      set_table_name "u_users" # Whatever you require
      belongs_to :company, :class_name => "OldCompany", :foreign_key => "fk_company_id"
    end
    

    Bingo,其他一切都会正常工作。

    【讨论】:

    • 请注意,set_table_name 已被删除,取而代之的是 self.table_name
    【解决方案2】:

    更新 扩展示例显示了表上的外键,还有几个示例显示了如何识别非标准列名以正确地在 rails 中路由。

    在您的应用中

    models
      |_ legacy
         |_ base.rb
         |_ user.rb
         |_ company.rb
      |_ user.rb
    

    类代码

    module Legacy
      class Base < ActiveRecord::Base
        self.abstract_class :true
        establish_connection "database here"
      end
    end
    
    module Legacy
      class User < Legacy::Base
        :has_many :companies, :class_name => 'Legacy::Company', :foreign_key => 'user_id'
      end
    end
    
    module Legacy
      class Company < Legacy::Base
        set_table_name 'companies'
        set_primary_key 'someId'
        belongs_to :user, :class_name => 'Legacy::User', :foreign_key => 'operator'
      end
    end
    

    在你需要的地方确定范围

    Legacy::User.new
    User.new
    
    Legacy::User.first.companies #=> returns array of Legacy::Companies
    

    【讨论】:

    • 这将如何与关联一起工作。假设我的用户有一家公司。如果我的 Legacy::User 有一个公司关联,它会默认为 Legacy 模块中的那个,还是(错误地)与较新的公司模型关联?
    • 你的表和列的名称是什么,我将修改示例
    【解决方案3】:

    您的选择是:

    • Magic Models 最后更新于 2009 年(截至 2012 年 11 月 1 日)

    • Connection Ninja 最后更新于 2010 年(截至 2012 年 11 月 1 日)

    • DB Charmer 上次更新时间大约为 6 个月前(截至 2012 年 11 月 1 日)

    • 覆盖模型中的establish_connection 以连接到所需的数据库

    • Activewarehouse-etl - 一个相当活跃的 gem,用于执行 db Extract Transform Load 工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多