Jam*_*hon 20 ruby validation ruby-on-rails state-machine ruby-on-rails-4
在state_machine gem 转换之前执行验证的正确语法是什么?
我试过以下,
before_transition :apple => :orange do
validate :validate_core
end
def validate_core
if core.things.blank?
errors.add(:core, 'must have one thing')
end
end
Run Code Online (Sandbox Code Playgroud)
但我得到以下错误,
undefined method `validate' for #<StateMachine::Machine:0x007ffed73e0bd8>
Run Code Online (Sandbox Code Playgroud)
我也试过写它,
state :orange do
validate :validate_core
end
Run Code Online (Sandbox Code Playgroud)
但是这会在保存记录后导致回滚,这不太理想.我想首先让状态机停止转换:orange.
核心问题是在我的控制器中我有依赖于结果的逻辑object.save.我对状态机的验证直到初始保存之后才会启动,因此保存返回为真,控制器继续逻辑,如果对象无效则不应该命中.
我通过手动测试有效性以及检查保存来解决这个问题,但感觉应该有一种方法可以在对象保存之前激活验证.
Sim*_*tti 27
该特定状态机的想法是在状态内嵌入验证声明.
state :orange do
validate :validate_core
end
Run Code Online (Sandbox Code Playgroud)
:validate_core只要对象转换为橙色,上面的配置就会执行验证.
event :orangify do
transition all => :orange
end
Run Code Online (Sandbox Code Playgroud)
我理解您对回滚的关注,但请记住,回滚是在事务中执行的,因此它非常便宜.
record.orangify!
Run Code Online (Sandbox Code Playgroud)
此外,请记住,您也可以使用不使用异常的非爆炸版本.
> c.orangify
(0.3ms) BEGIN
(0.3ms) ROLLBACK
=> false
Run Code Online (Sandbox Code Playgroud)
也就是说,如果您想基于转换前使用不同的方法,那么您只需要知道如果回调返回false,则转换将停止.
before_transition do
false
end
> c.orangify!
(0.2ms) BEGIN
(0.2ms) ROLLBACK
StateMachine::InvalidTransition: Cannot transition state via :cancel from :purchased (Reason(s): Transition halted)
Run Code Online (Sandbox Code Playgroud)
请注意,事务始终处于启动状态,但如果回调处于最开始状态,则可能不会执行任何查询.
在before_transaction接受一些PARAMS.您可以生成对象和事务实例.
before_transition do |object, transaction|
object.validate_core
end
Run Code Online (Sandbox Code Playgroud)
事实上你可以通过事件限制它
before_transition all => :orange do |object, transaction|
object.validate_core # => false
end
Run Code Online (Sandbox Code Playgroud)
在这种情况下,validate_core应该是一个返回true/false的简单方法.如果你想使用定义的验证链,那么我想到的是调用valid?模型本身.
before_transition all => :orange do |object, transaction|
object.valid?
end
Run Code Online (Sandbox Code Playgroud)
但请注意,您无法在交易范围之外运行交易.实际上,如果检查代码perform,您将看到回调在事务中.
# Runs each of the collection's transitions in parallel.
#
# All transitions will run through the following steps:
# 1. Before callbacks
# 2. Persist state
# 3. Invoke action
# 4. After callbacks (if configured)
# 5. Rollback (if action is unsuccessful)
#
# If a block is passed to this method, that block will be called instead
# of invoking each transition's action.
def perform(&block)
reset
if valid?
if use_event_attributes? && !block_given?
each do |transition|
transition.transient = true
transition.machine.write(object, :event_transition, transition)
end
run_actions
else
within_transaction do
catch(:halt) { run_callbacks(&block) }
rollback unless success?
end
end
end
# ...
end
Run Code Online (Sandbox Code Playgroud)
要跳过事务,您应该修改state_machine,以便转换方法(例如orangify!)在转换之前检查记录是否有效.
这是你应该实现的一个例子
# Override orangify! state machine action
# If the record is valid, then perform the actual transition,
# otherwise return early.
def orangify!(*args)
return false unless self.valid?
super
end
Run Code Online (Sandbox Code Playgroud)
当然,你不能手动为每个方法做到这一点,这就是为什么你应该修补库来实现这个结果.
| 归档时间: |
|
| 查看次数: |
4964 次 |
| 最近记录: |