2016-10-29 71 views
3

我再次開始使用Rails,並遇到了一個難題,我現在覺得這很難理解。當談到使用數據庫時,我有點小氣,所以請原諒我,如果這是相當基本的。將遺留數據遷移到導軌中的新模型

我有一箇舊的Rails應用程序,我不再希望符合數據模型。該模型應該被棄用,以支持更輕,更簡單的模型。

較舊的應用程序也非常單一,所以我試圖將它分解成較小的服務組件。

因此,這引出我的疑問,因爲它通常不贊成使用來自單個模型的多個數據庫......將舊模型中存儲的數據轉換爲新模型的最佳方法是什麼,一次一個服務?

例如,讓我們假設我在舊的和新的都有一個用戶模型。在舊模型中,用戶有很多列,但不是所有列都應該使用新模型。

這可能是一個例子,從用戶被限制到舊模型中的單個地址,以能夠分配一個到多個關係,其中地址在他們自己的模型中被拆分並且僅使用外部引用鑰匙什麼的。

編輯1:

的目標最終是在同一時間從傳統模式的數據庫中的數據虹吸到新的模型的數據庫,儘可能方便,一個數據集。編輯2:

最初發布從我的手機。這裏有幾個例子可能有助於提出建議。

舊模式

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 

所以,基本上...我希望能夠從舊的模式中取數據,說一個品牌「的名字「列並將其相關值抽取到新模型中,這樣值就會在完全不同的postgresql實例的公司」companyName「列中結束。

+0

我認爲你應該先建立你的新應用程序,並製作一些自定義的種子數據來幫助開發。然後,當你感覺完成後,編寫一個遷移腳本。編寫一些自動化測試來驗證數據完全遷移非常重要。這是一個有點魯莽的任務,但它必須完成。如果存在關聯對象存在的驗證,請確保以正確的順序創建記錄。 –

+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 

在新的rake任務(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使用固定的約定來構建。每次都不遵守該公約會導致問題和額外費用。我已經看過很多次了。每當我看到有人偏離那個慣例時,他們遇到的麻煩都比他們預想的要多得多。他們打破了很多「Rails魔法」。

+0

這種方法非常完美!我不僅僅依賴更多的Rails的「魔術」,而且我實際上也學習了創建自定義Rake動作! –

1

採取TDD方法肯定會幫助您覆蓋更多地面。

查看DataMapper,您可以在Rake任務中使用它或完全分離Ruby腳本。這樣,您可以遍歷應用程序數據(來自Active Record),並通過DataMapper將其傳遞到新的Postgres數據庫。

您可以連接到新的DB這樣,

DataMapper.setup(:default, 'postgres://user:[email protected]/database') 
+0

考慮到OP的應用程序使用activerecord,在這種情況下使用datamapper的好處是什麼? –

+0

我看到它的方式是,OP可以通過新的應用程序來測試,並且從我記得的地方看,ActiveRecord被設計爲始終連接到單個數據庫(但是,可以設置單獨的頂級類和獲得一個單獨的AR實例到另一個數據庫)。 然後,您可以使用DataMapper(因爲它重量輕)連接到第二個數據庫,或者如果需要,可以使用第二個AR實例,但我不確定推薦或不推薦多少。 –