将旧数据迁移到rails中的新模型

时间:2016-10-29 02:00:05

标签: ruby-on-rails ruby database postgresql ruby-on-rails-4

我再次开始使用Rails并遇到了一个难题,我现在觉得很恐怖。在使用数据库方面,我有点像菜鸟,所以如果这是相当基本的话,请原谅我。

我有一个较旧的Rails应用程序,其中包含我不再希望遵循的数据模型。该模型应该被弃用,而不是更轻,更简单的模型。

较旧的应用程序也非常单一,所以我试图将其分解为更小的服务组件。

所以这引出了我的问题,因为它通常不赞成使用单个模型中的多个数据库...将旧模型中存储的数据转换为新模型的最佳方法是什么?一次?

例如,假设我在旧版和新版中都有用户模型。在旧模型中,用户有许多列,并非所有列都应该用于新模型。

这方面的一个例子可能是从用户被限制为旧模型中的单个地址变为能够分配一对多关系,其中地址在他们自己的模型中被拆分并且使用外键简单地引用什么的。

编辑1:

目标最终是尽可能容易地将来自遗留模型数据库的数据虹吸到新模型的数据库中,一次一个数据集。

编辑2:

最初是从我的手机发布的。以下是一些可能有助于提出建议的例子。

OLD MODEL

  create_table "brands", force: :cascade do |t|
    t.string   "name"
    t.string   "url"
    t.string   "logo"
    t.boolean  "verified"
    t.datetime "created_at",                                   null: false
    t.datetime "updated_at",                                   null: false
    t.boolean  "hidden",                       default: false
    t.string   "facebook_url"
    t.string   "twitter_handle"
    t.string   "pinterest_handle"
    t.string   "google_plus_url"
    t.string   "address_street1"
    t.string   "address_street2"
    t.string   "address_street3"
    t.string   "address_city"
    t.string   "address_state"
    t.string   "address_zip"
    t.string   "address_country"
    t.string   "email"
    t.string   "phone"
    t.string   "story_title"
    t.text     "story_text"
    t.string   "story_photo"
  end

新模型

  create_table "companies", force: :cascade do |t|
    t.string   "companyName",                               null: false
    t.string   "companyURL",                                null: false
    t.boolean  "companyIsActive",                 default: true,   null: false
    t.boolean  "companyDataIsVerified",           default: false,  null: false
    t.string   "companyLogoFileURL"
    t.datetime "companyFoundedOnDate"
    t.integer  "companyHQLocationID"
    t.integer  "companyParentCompanyID"
    t.integer  "companyFirstSuggestedByID"
    t.string   "companyFacebookURL"
    t.string   "companyGooglePlusURL"
    t.string   "companyInstagramURL"
    t.string   "companyPinterestURL"
    t.string   "companyTwitterURL"
    t.string   "companyStoryTitle"
    t.text     "companyStoryContent"
    t.string   "companyStoryImageFileURL"
    t.boolean  "companyIsHiddenFromIndex",        default: false, null: false
    t.integer  "companyDataScraperID"
    t.datetime "created_at",                                null: false
    t.datetime "updated_at",                                null: false
  end

所以,基本上......我希望能够从旧模型中获取数据,比如一个品牌" name"列并将其相关值吸收到新模型中,因此价值最终会出现在公司" companyName"一个完全不同的postgresql实例的列。

2 个答案:

答案 0 :(得分:3)

多次这样做之后,我可以告诉你,最简单的事情就是创建一个简单的rake任务,迭代第一个集合并在新集合中创建项目。

无需使用DataMapper之类的东西。您已经拥有ActiveRecord,可以简单地定义每个模型使用的数据库连接。

config/database.yml

brand_database:
  adapter: postgresql
  host: brand_host
  username: brand_user
  password: brand_pass
  database: brand_db

company_database:
  adapter: postgresql
  host: company_host
  username: company_user
  password: company_pass
  database: company_db

在你的模特中:

class Brand < ActiveRecord::Base
  establish_connection :brand_database
end

class Company < ActiveRecord::Base
  establish_connection :company_database
end

在新的佣金任务(lib/tasks/db.rake)中:

# lib/tasks/db.rake
namespace :db do
  desc "Migrate brand records to company records"
  task :migrate_brands_to_companies, [] => :environment do
    Brand.find_each do |brand|
      Company.find_or_initialize_by(companyName: brand.name) do |company|
        puts "\n\tCreating Company record for #{brand.name}"
        company.companyURL               = brand.url
        company.companyLogoFileURL       = brand.logo
        company.companyTwitterURL        = "https://twitter.com/#{brand.twitter_handle}"
        company.companyIsHiddenFromIndex = brand.hidden
        company.created_at               = brand.created_at
        company.updated_at               = brand.updated_at
        company.save!
      end
    end
  end
end

最后,运行rake任务:

$ rake db:migrate_brands_to_companies

我需要这样说:Rails是使用一个可靠的约定构建的。不遵守该惯例将导致每次都出现问题和额外费用。我见过这么多次了。每当我看到有人偏离这个惯例时,他们遇到的麻烦比他们预期的要大得多。他们打破了很多&#34; Rails魔术&#34;。

答案 1 :(得分:1)

采用TDD方法肯定会帮助你覆盖更多的基础。

查看DataMapper,您可以在Rake任务中使用或完全分离Ruby脚本。这样,您可以迭代应用程序数据(来自Active Record)并通过DataMapper将其传递给新的Postgres数据库。

您可以像这样连接到新的数据库

DataMapper.setup(:default, 'postgres://user:password@hostname/database')