2016-06-29 86 views
1

在我在我的ActiveRecords使用Ruby的工作流程使用寶石:WorkflowRuby的工作流程問題遷移

現有運行代碼包含:

  • 我有一個ActiveRecord:X
  • 我有已遷移兩次:
    • (Ref1) CreateX migration(它創建表X)
    • (REF2) CreateInitialEntryInX遷移(在表X創建一個條目)

新變化:

  • 現在,我想補充的工作流程在ActiveRecord X中,因此我做了:
    • (REF3)我增加了工作流代碼中的ActiveRecord型號X(提的是:地位,我的工作流場)
    • (至Ref4) AddStatusFieldToX遷移(添加:在表X狀態字段)

現在,當我運行rake db:遷移後發生更改時,(Ref2) break cos遷移查找:狀態字段,因爲它在工作流程部分的ActiveRecord模型中提到,但是:status字段尚未添加爲遷移(Ref4)尚未執行。

因此,當所有遷移按順序運行時,所有構建失敗,對此的任何解決方案? 我不想重新排序任何遷移或編輯任何舊的現有遷移。

我的模型看起來像:

class BaseModel < ActiveRecord::Base 
     # 
     # Workflow to define states of Role 
     # 
     # Initial State => Active 
     # 
     # # State Diagram:: 
     # Active --soft_delete--> Deleted 
     # Deleted 
     # 
     # * activate, soft_delete are the event which triggers the state transition 
     # 
     include Workflow 
     workflow_column :status 
     workflow do 
     state :active, X_MODEL_STATES::ACTIVE do 
      event :soft_delete, transitions_to: :deleted 
     end 
     state :deleted, X_MODEL_STATES::DELETED 

     on_transition do |from, to, event, *event_args| 
      self.update_attribute(:status, to) 
     end 
     end 

     def trigger_event(event) 
     begin 
      case event.to_i 
      when X_MODEL_EVENTS::ACTIVATE 
       self.activate! 
      when X_MODEL_EVENTS::SOFT_DELETE 
       self.soft_delete! 
      end 
     rescue .... 
     end 
    end 

    class X_MODEL_STATES 
    ACTIVE  = 1 
    DELETED  = 2 
    end 

    class X_MODEL_EVENTS 
    ACTIVATE  = 1 
    SOFT_DELETE = 2 
    end 

# Migrations(posting Up functions only - in correct sequence) 
#-------------------------------------------------- 

#1st: Migration - This is already existing migration 
CreateX < ActiveRecord::Migration 
    def up 
    create_table :xs do |t| 
     t.string :name 
     t.timestamps null: false 
    end 
    end 
end 

#2nd: Migration - This is already existing migration 
CreateInitialX < ActiveRecord::Migration 
    def up 
    X.create({:name => 'Kartik'}) 
    end 
end 

#3rd: Migration - This is a new migration 
AddStatusToX < ActiveRecord::Migration 
    def up 
    add_column :xs, :status, :integer 
    x.all.each do |x_instance| 
     x.status = X_MODEL_STATES::ACTIVE 
     x.save! 
    end 
    end 
end 

所以,當遷移#2運行時,它試圖找到:狀態字段寫是的X_MODEL_STATES::ACTIVE初始值,因爲它是在Active Record的模型文件中提到工作流程爲:workflow_column :status並且未找到該字段爲遷移#3尚未執行。

+0

請張貼一些代碼和實際的例外,也是什麼原因,沒有把正確的順序遷移? – fabriciofreitag

+0

@onionfeelings,因爲早些時候的遷移即Ref1和Ref2已經在生產中,並且自從現在幾個月開始運行。這是由於添加要求而正在進行的遷移。這個問題不會在生產中進行,因爲只有新的遷移將運行。 但是,如果有人分叉代碼並在開發環境中運行,遷移將中斷(我想避免) – kattybilly

+0

你可以發佈你的代碼嗎?理論上,如果你這樣做: add_column:TABLE_X,:STATUS_ID,:整數 你不應該有任何問題,並且仍然Rails會正確處理的關聯,因爲你下面的約定 – fabriciofreitag

回答

0

謝謝全部 我找到了解決方案,我在這裏發佈。在此問題上的問題是:

  • :status字段添加到ActiveRecord Model X沒有註釋掉的代碼的工作流程,而不是讓工作流程遷移過程中禁止在Table X一個實例的創建。
  • 其次,按照@ 007sumit的規定向它添加一個if條件。
  • 第三,要能夠重新加載模型遷移與Model X

更新column_information編寫整個代碼的解決方案在這裏:

class BaseModel < ActiveRecord::Base 
     # 
     # Workflow to define states of Role 
     # 
     # Initial State => Active 
     # 
     # # State Diagram:: 
     # Active --soft_delete--> Deleted 
     # Deleted 
     # 
     # * activate, soft_delete are the event which triggers the state transition 
     # 

     # if condition to add workflow only if :status field is added 
     if self.attribute_names.include?('status') 
     include Workflow 
     workflow_column :status 
     workflow do 
      state :active, X_MODEL_STATES::ACTIVE do 
      event :soft_delete, transitions_to: :deleted 
      end 
      state :deleted, X_MODEL_STATES::DELETED 

     end 
     end 

     def trigger_event(event) 
     ... 
     end 
    end 

    class X_MODEL_STATES 
    ... 
    end 

    class X_MODEL_EVENTS 
    ... 
    end 

# Migrations(posting Up functions only - in correct sequence) 
#-------------------------------------------------- 

#1st: Migration - This is already existing migration 
CreateX < ActiveRecord::Migration 
    def up 
    create_table :xs do |t| 
     t.string :name 
     t.timestamps null: false 
    end 
    end 
end 

#2nd: Migration - This is already existing migration 
CreateInitialX < ActiveRecord::Migration 
    def up 
    X.create({:name => 'Kartik'}) 
    end 
end 

#3rd: Migration - This is a new migration to add status field and 
# modify status value in existing entries in X Model 
AddStatusToX < ActiveRecord::Migration 
    def up 
    add_column :xs, :status, :integer 

    # This resets Model Class before executing this migration and 
    # Workflow is identified from the if condition specified which was 
    # being skipped previously without this line as Model Class is 
    # loaded only once before all migrations run. 
    # Thanks to post: http://stackoverflow.com/questions/200813/how-do-i-force-activerecord-to-reload-a-class 

    x.reset_column_information 
    x.all.each do |x_instance| 
     x.status = X_MODEL_STATES::ACTIVE 
     x.save! 
    end 
    end 
end 

@斯坦 - brajewski現在,這個代碼可以去一個部署。 感謝所有的投入:)

+1

偉大的你做到了。這仍然是一個臨時代碼的黑客,因爲你不希望你的模型來對所有這些屬性永遠:-) –

+0

你應該接受別人的答案所有這些如果,我投@ 007sumit就像你剛纔複製他的答案,你的代碼和提出了一個新的答案。您使用007sumit代碼作爲解決方案,因此請接受007sumit答案。這就是工作原理。 –

+0

所以這不是一個完整的答案。它沒有完全解決它。答案是@ 007sumit的答案和帖子中提供的答案的組合:http://stackoverflow.com/questions/200813/how-do-i-force-activerecord-to-reload-a-class。因此我加了正確的答案,這是兩者的結合。 M很高興接受任何人的回答,但他們不完整,因此不能接受。雖然upvoted可用的。 – kattybilly

1

這是一種痛苦,因爲您的模型需要保持遷移一致。我不知道任何汽車解決方案。

理論上最好的方法是讓模型代碼版本綁定遷移。但我不知道任何允許這個的系統。

每當我做大模型重構我遇到這個問題。這種情況的可能解決方案。

  1. 生產運行遷移手動,以確保遷移和模型

  2. 之間consitent狀態模型臨時註釋掉工作流程代碼運行阻止遷移,再部署,再取消註釋工作流代碼,並與部署繼續前進,下次遷移

  3. 版本在分支機構上的遷移和模型更改,因此它們是一致的。部署到生產並通過塊運行遷移

  4. 在模型代碼中包含臨時解決方法,並在部署生產遷移後將其從源移除。

  5. 向後兼容的遷移代碼中的Monkey-patch模型。在您的情況,這將是從型號代碼中動態刪除「工作流程」,這可能是困難的,然後運行遷移

所有的解決方案是某種骯髒的黑客,但它不容易有遷移和模型代碼版本。最好的方法是以塊的形式進行部署,或者如果需要一次部署,請在模型中使用一些臨時代碼,並在生產部署後將其刪除。

+0

感謝解決方案,事實上他們是黑客,但即使我做了上述任何解決方案或如上所述,部署在塊中,我可能會擺脫生產或其他現有的開發部署,但仍然會遇到的問題是: >如果有人讓我的回購構建項目,出於同樣的原因,系統上的遷移仍然會中斷。 – kattybilly

+0

我已經發布瞭解決方案。感謝您的寶貴意見@StanBrajewski – kattybilly

+0

@kattybilly當用戶克隆新的回購協議和啓動項目,他不應該開始遷移,但是從DB/schema.rb創建一個新的數據庫 - 它在Rails的文檔HTTP說:// edgeguides。 rubyonrails.org/active_record_migrations.html#schema-dumping-and-you「通過重播整個遷移歷史記錄,不需要(也很容易出錯)部署新的應用程序實例,它更簡單快捷將當前模式的描述加載到數據庫中。「 –

2

您可以通過檢查column_name來結束工作流程代碼。

if self.attribute_names.include?('status') 
    include Workflow 
    workflow_column :status 
    workflow do 
    ... 
    end 
end 

這將導致只有在'AddStatusToTable'遷移成功運行後,纔會運行工作流代碼。

+0

那麼這樣做是: - 遷移運行之前,初始化Rails應用程序,而不會因爲它在被繞過了工作流程的'如果條件(你提到)' - 然後,**遷移#2 **移民工程罰款和成功,但是當**遷移#3 **運行時,它不與代碼做任何事情:爲所加載的模型是不是一個新的列,再加上工作流仍不知何故 'X_MODEL_STATES :: ACTIVE'控制模型(儘管'如果{條件}')。 – kattybilly

+0

所有執行遷移後,觀察是: 所有'X Model'條目有':狀態= nil'儘管這種變化由你的建議,儘管有**遷移#3 **包含'初始化:status'價值' X_MODEL_STATES :: ACTIVE'這是'1' – kattybilly