2010-05-22 49 views
6

有幾次我一直在想要重構某個模型的設計,並最終將更新邏輯放入遷移中。然而,據我瞭解,這不是好的做法(特別是因爲鼓勵您使用您的模式文件進行部署,而不是您的遷移)。你如何處理這些問題?在您的遷移中添加更新邏輯

爲了表達我的意思,說我有一個用戶模型。由於我認爲只有兩種用戶,即「普通」用戶和管理員,我選擇使用簡單的布爾字段來告訴用戶是否是管理員。

但是,經過一段時間後,我想我需要一些第三種用戶,也許是一個主持人或類似的東西。在這種情況下,我添加一個UserType模型(以及相應的遷移),以及從用戶表中刪除「admin」標誌的第二次遷移。問題來了。在「add_user_type_to_users」遷移中,我必須將管理標誌值映射到用戶類型。此外,爲了做到這一點,用戶類型必須存在,這意味着我不能使用種子文件,而是在遷移中創建用戶類型(也被認爲是不好的做法)。這裏有一些代表情況的虛構代碼:

class CreateUserTypes < ActiveRecord::Migration 
    def self.up 
     create_table :user_types do |t| 
      t.string :name, :nil => false, :unique => true 
     end 

     #Create basic types (can not put in seed, because of future migration dependency) 
     UserType.create!(:name => "BASIC") 
     UserType.create!(:name => "MODERATOR") 
     UserType.create!(:name => "ADMINISTRATOR") 
    end 

    def self.down 
     drop_table :user_types 
    end 
end 

class AddTypeIdToUsers < ActiveRecord::Migration 
    def self.up 
     add_column :users, :type_id, :integer 

     #Determine type via the admin flag 
     basic = UserType.find_by_name("BASIC") 
     admin = UserType.find_by_name("ADMINISTRATOR") 
     User.all.each {|u| u.update_attribute(:type_id, (u.admin?) ? admin.id : basic.id)} 

     #Remove the admin flag 
     remove_column :users, :admin 

     #Add foreign key 
     execute "alter table users add constraint fk_user_type_id 
      foreign key (type_id) references user_types (id)" 
    end 

    def self.down 
     #Re-add the admin flag 
     add_column :users, :admin, :boolean, :default => false 

     #Reset the admin flag (this is the problematic update code) 
     admin = UserType.find_by_name("ADMINISTRATOR") 

     execute "update users set admin=true where type_id=#{admin.id}" 

     #Remove foreign key constraint 
     execute "alter table users drop foreign key fk_user_type_id" 

     #Drop the type_id column 
     remove_column :users, :type_id 
    end 
end 

正如你可以看到有兩個有問題的部分。首先是第一個模型中的行創建部分,如果我想要在一行中運行所有遷移,那麼這是必需的,然後第二個遷移中的「更新」部分將「admin」列映射到「type_id」列。

有什麼建議嗎?

回答

1

我發現它比使用舊User.admin載入UserType更常用的fk,而我經常會這麼想。

如果你使用fk,你會得到令用戶感到困惑的醜陋mysql錯誤。否則,如果您使用AR驗證和掛鉤來強制引用完整性,那麼您將得到漂亮且集成良好的錯誤消息,這些消息不會中斷應用程序的用戶體驗流。

不要擔心一次只能運行一次的遷移,並考慮您在代碼之外放置的業務邏輯。

這是所有意見/慣例的問題,但我希望你發現我的見解有所幫助。

+0

當涉及到外鍵時,我發現它們非常有用,特別是在處理buisness關鍵數據時。它可以幫助我避免懸浮數據,並檢測我是否錯過了Rails方面的應用鉤子等。雖然你是對的,但他們可能會給你一些醜陋的錯誤信息。 – 2010-05-22 07:52:34

+1

我明白了,這是一個選擇的問題。如果超出備份的數據完整性超過了UX,fk就是要走的路。 在這種情況下,你有一個插件來管理遷移中的fk: http://agilewebdevelopment.com/plugins/foreign_key_migrations – Oinak 2010-05-22 12:51:12

+0

好的。謝謝你的提示! – 2010-05-24 06:23:08

0

文件DB/seeds.rb通常用於此目的 - 放置在有記錄將被加載的 rake db:setup

但是一部分,我總是發現軌道落下這個問題。 我一直在想寫一個給你一個db /種子文件夾的插件,有用於添加記錄(可能是.yml)的有日期戳的種子文件,並跟蹤系統表中的種子數據以便它可以被恢復/更新。

+1

正如您在代碼中看到的那樣,我不能使用種子,因爲我想一次應用多次遷移,而最後一次遷移取決於數據庫中是否有數據。如果每次遷移可以有一個種子文件,並且種子文件將在遷移之間應用,那將會很不錯。所以首先20100524 ... do_something.rb運行,然後20100524 ... seed_something.rb執行此遷移所需的種子。 – 2010-05-24 06:26:37