We need to add a feature which allows a user to decide, before he make a change to a model, when will this change will take affect (e.g. from tomorrow at 19:43)
我们需要添加一个功能,允许用户在对模型进行更改之前决定何时此更改将生效(例如从明天19:43开始)
The problem we've is that our model has many dependencies with many validations and there is a chance that future changes will conflict one another :
我们遇到的问题是我们的模型有许多依赖性和许多验证,未来的变化可能会相互冲突:
- Make change A to take place tomorrow (pass validation test)
- 明天进行变更A(通过验证测试)
- Make change B now - this change might have cause change A to be invalid.
- 立即进行更改B - 此更改可能导致更改A无效。
Is there a known solution/Gem for that issue? What is the best approach to tackle this?
该问题是否有已知的解决方案/宝石?解决这个问题的最佳方法是什么?
Thanks.
谢谢。
4 个解决方案
#1
1
You could duplicate the web server and DB, and have one instance for today and one for tomorrow. At midnight, override the "tomorrow" DB with "today" one.
您可以复制Web服务器和数据库,并且今天有一个实例,明天有一个实例。在午夜,用“今天”覆盖“明天”数据库。
#2
1
I suggest you to use State Machines. You can read on wiki for a quick introduction. And there are many gems you can use: at ruby-toolbox. Each of these has its pros and cons, but the standard behaviour is allow define states, events and transitions between events, also some of them provides callbacks, validations and conditions.
我建议你使用状态机。您可以在维基上阅读以获得快速介绍。你可以使用很多宝石:ruby-toolbox。这些中的每一个都有其优点和缺点,但标准行为是允许定义事件之间的状态,事件和转换,其中一些还提供回调,验证和条件。
I've been using simple_states which work fine even with complex set of models updated simultaneously. It has few lines of code, and I think that this can help when things goes wrong.
我一直在使用simple_states,即使同时更新了一组复杂的模型也能正常工作。它几行代码,我认为这可以在出现问题时提供帮助。
It depends on your system business rules, but you can set a state on the point "1. Make change A to take place tomorrow (pass validation test)", as "frozen" perhaps, and then when came the point "2. Make change B now - this change might have cause change A to be invalid", validate if this change can be performed with that status.
这取决于你的系统业务规则,但是你可以设置一个状态点“1.明天发生变更A(通过验证测试)”,也许是“冻结”,然后当点“2”时现在更改B - 此更改可能导致更改A无效“,验证是否可以使用该状态执行此更改。
Then when your system will changes, it will be easy to add new events, statuses, and transitions and keep the system aligned with the updated business rules.
然后,当您的系统发生变化时,可以轻松添加新事件,状态和转换,并使系统与更新的业务规则保持一致。
#3
1
Looks like a very old question. But since I implemented something similar, I am answering this:
看起来像一个很老的问题。但是由于我实现了类似的东西,我正在回答这个问题:
This can be easily achieved using the Sidekiq gem (which works with Redis). I've actually used this gem to solve similar situation.
使用Sidekiq gem(可与Redis配合使用)可轻松实现此目的。我实际上用这个宝石解决了类似的情况。
The main prominent use of Sidekiq is to incorporate the Background Jobs in Rails apps. Along with that Sidekiq provides additional functionalities like delaying in a particular call on an ActiveRecord object.
Sidekiq的主要用途是在Rails应用程序中加入后台作业。与Sidekiq一起提供了其他功能,例如延迟ActiveRecord对象上的特定调用。
This is how it's to be done:
这是如何做到的:
User.delay_for(2.weeks).whatever
Checkout more options here:
在这里结帐更多选项:
https://github.com/mperham/sidekiq/wiki/Delayed-extensions
https://github.com/mperham/sidekiq/wiki/Delayed-extensions
#4
1
I suggest you use rollback functionality: http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
我建议你使用回滚功能:http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
Lets say you already have Change A in the queue for tomorrow which passed validation. And someone is making a Change B to same model, you can do:
假设您已经在明天的队列中有更改A通过验证。有人正在将变更B变为同一模型,您可以这样做:
- open rollback transaction.
- 打开回滚事务。
- Save new Change B to model
- 将新的变更B保存到模型中
- Validate Change A that's waiting in the queue.
- 验证正在队列中等待的更改A.
- If validation on Change A fails, rollback transaction which will return all Changes B to unchanged state.
- 如果对更改A的验证失败,则回滚事务将使所有更改B返回到未更改状态。
- Notify user that is doing Change B that his change is conflicting Change A.
- 通知正在进行变更B的用户,他的变更是冲突的变更A.
Simplified Meta code example would be:
简化的元代码示例如下:
Transient.transaction do
model = get_transient_model
model.change = change_B
model.save
model.change = QueueChanges.get_change_A
if not model.valid?
notification_system.notify_user_about_conflict!
raise ActiveRecord::Rollback, "Conflict!"
else
# we are good to go!
end
end
#1
1
You could duplicate the web server and DB, and have one instance for today and one for tomorrow. At midnight, override the "tomorrow" DB with "today" one.
您可以复制Web服务器和数据库,并且今天有一个实例,明天有一个实例。在午夜,用“今天”覆盖“明天”数据库。
#2
1
I suggest you to use State Machines. You can read on wiki for a quick introduction. And there are many gems you can use: at ruby-toolbox. Each of these has its pros and cons, but the standard behaviour is allow define states, events and transitions between events, also some of them provides callbacks, validations and conditions.
我建议你使用状态机。您可以在维基上阅读以获得快速介绍。你可以使用很多宝石:ruby-toolbox。这些中的每一个都有其优点和缺点,但标准行为是允许定义事件之间的状态,事件和转换,其中一些还提供回调,验证和条件。
I've been using simple_states which work fine even with complex set of models updated simultaneously. It has few lines of code, and I think that this can help when things goes wrong.
我一直在使用simple_states,即使同时更新了一组复杂的模型也能正常工作。它几行代码,我认为这可以在出现问题时提供帮助。
It depends on your system business rules, but you can set a state on the point "1. Make change A to take place tomorrow (pass validation test)", as "frozen" perhaps, and then when came the point "2. Make change B now - this change might have cause change A to be invalid", validate if this change can be performed with that status.
这取决于你的系统业务规则,但是你可以设置一个状态点“1.明天发生变更A(通过验证测试)”,也许是“冻结”,然后当点“2”时现在更改B - 此更改可能导致更改A无效“,验证是否可以使用该状态执行此更改。
Then when your system will changes, it will be easy to add new events, statuses, and transitions and keep the system aligned with the updated business rules.
然后,当您的系统发生变化时,可以轻松添加新事件,状态和转换,并使系统与更新的业务规则保持一致。
#3
1
Looks like a very old question. But since I implemented something similar, I am answering this:
看起来像一个很老的问题。但是由于我实现了类似的东西,我正在回答这个问题:
This can be easily achieved using the Sidekiq gem (which works with Redis). I've actually used this gem to solve similar situation.
使用Sidekiq gem(可与Redis配合使用)可轻松实现此目的。我实际上用这个宝石解决了类似的情况。
The main prominent use of Sidekiq is to incorporate the Background Jobs in Rails apps. Along with that Sidekiq provides additional functionalities like delaying in a particular call on an ActiveRecord object.
Sidekiq的主要用途是在Rails应用程序中加入后台作业。与Sidekiq一起提供了其他功能,例如延迟ActiveRecord对象上的特定调用。
This is how it's to be done:
这是如何做到的:
User.delay_for(2.weeks).whatever
Checkout more options here:
在这里结帐更多选项:
https://github.com/mperham/sidekiq/wiki/Delayed-extensions
https://github.com/mperham/sidekiq/wiki/Delayed-extensions
#4
1
I suggest you use rollback functionality: http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
我建议你使用回滚功能:http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
Lets say you already have Change A in the queue for tomorrow which passed validation. And someone is making a Change B to same model, you can do:
假设您已经在明天的队列中有更改A通过验证。有人正在将变更B变为同一模型,您可以这样做:
- open rollback transaction.
- 打开回滚事务。
- Save new Change B to model
- 将新的变更B保存到模型中
- Validate Change A that's waiting in the queue.
- 验证正在队列中等待的更改A.
- If validation on Change A fails, rollback transaction which will return all Changes B to unchanged state.
- 如果对更改A的验证失败,则回滚事务将使所有更改B返回到未更改状态。
- Notify user that is doing Change B that his change is conflicting Change A.
- 通知正在进行变更B的用户,他的变更是冲突的变更A.
Simplified Meta code example would be:
简化的元代码示例如下:
Transient.transaction do
model = get_transient_model
model.change = change_B
model.save
model.change = QueueChanges.get_change_A
if not model.valid?
notification_system.notify_user_about_conflict!
raise ActiveRecord::Rollback, "Conflict!"
else
# we are good to go!
end
end