我使用Gem:Workflow
在我的ActiveRecords中使用Ruby Workflow现有的运行代码包含:
新变化:
现在,当我在更改后运行rake db:migrate时,(Ref2)中断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 Model文件工作流中提到:{ {1}}并且未找到迁移#3 尚未执行的字段。
答案 0 :(得分:2)
您可以通过检查column_name来包装工作流代码。
if self.attribute_names.include?('status')
include Workflow
workflow_column :status
workflow do
...
end
end
这将导致仅在“AddStatusToTable&#39;”之后运行工作流程代码。迁移成功运行。
答案 1 :(得分:1)
这很痛苦,因为您的模型需要与迁移保持一致。我不知道任何汽车解决方案。
理论上最好的方法是将模型代码版本与迁移结合起来。但我不知道任何允许这种情况的系统。
每次我做大模型重构我都会遇到这个问题。这种情况的可能解决方案。
手动运行生产迁移以确保迁移和模型之间的合作状态
暂时注释掉模型中的工作流代码以运行阻止迁移,然后部署,然后取消注释工作流代码,继续部署和下次迁移
分支上的版本迁移和模型更改,因此它们是一致的。部署到生产并按块运行迁移
在模型代码中包含临时解决方法,并在部署生产迁移后从源代码中删除它们。
迁移代码中的Monkey-patch模型,用于向后兼容。在您的情况下,这将是从模型代码中动态删除“工作流程”,这可能很难,然后运行迁移
所有解决方案都是某种肮脏的黑客攻击,但是迁移和模型代码版本化并不容易。最好的方法是以块的形式进行部署,或者如果需要一次部署所有部分,请在模型中使用一些临时代码,并在生产部署后将其删除。
答案 2 :(得分:0)
感谢所有 我找到了解决方案,我在这里发布。这里要问的问题是:
:status
字段添加到ActiveRecord Model X
而不注释掉工作流程代码,并且不允许工作流程在迁移期间禁止在Table X
中创建实例。Model X
在此编写完整的代码解决方案:
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
@ stan-brajewski现在,此代码可以在一个部署中进行。 感谢所有人的投入:)