gpt4 book ai didi

ruby-on-rails - 在 state_machine gem 上持久化之前的验证

转载 作者:数据小太阳 更新时间:2023-10-29 06:30:59 24 4
gpt4 key购买 nike

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

但是我得到以下错误,

undefined method `validate' for #<StateMachine::Machine:0x007ffed73e0bd8>

我也试过把它写成,

state :orange do
validate :validate_core
end

但这会导致记录保存后回滚,不太理想。我想首先阻止状态机转换为 :orange

核心问题是,在我的 Controller 中,我的逻辑依赖于 object.save 的结果。我对状态机的验证直到初始保存后才会启动,因此保存返回为 true,并且 Controller 继续逻辑,如果对象无效,它不应该命中。

除了检查保存之外,我还通过手动测试有效性来解决这个问题,但感觉应该有一种方法可以在对象保存之前触发验证。

最佳答案

该特定状态机的想法是将验证声明嵌入到状态中。

state :orange do
validate :validate_core
end

上面的配置将在对象转换为橙色时执行验证 :validate_core

event :orangify do
transition all => :orange
end

我理解您对回滚的担忧,但请记住,回滚是在事务中执行的,因此成本非常低。

record.orangify!

此外,请记住您还可以使用不使用异常的非 bang 版本。

> c.orangify
(0.3ms) BEGIN
(0.3ms) ROLLBACK
=> false

也就是说,如果您想使用基于转换前的不同方法,那么您只需要知道如果回调返回 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)

请注意,事务始终会启动,但如果回调在最开始时可能不会执行任何查询。

before_transaction 接受一些参数。您可以生成对象和事务实例。

before_transition do |object, transaction|
object.validate_core
end

事实上你可以通过事件来限制它

before_transition all => :orange do |object, transaction|
object.validate_core # => false
end

在这种情况下,validate_core 应该是一个返回 true/false 的简单方法。如果您想使用定义的验证链,那么我想到的是在模型本身上调用 valid?

before_transition all => :orange do |object, transaction|
object.valid?
end

但是请注意,您不能在事务范围之外运行事务。事实上,如果您检查 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

要跳过事务,您应该猴子修补 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

当然,您不能为每个方法手动执行此操作,这就是为什么您应该猴子修补库以实现此结果的原因。

关于ruby-on-rails - 在 state_machine gem 上持久化之前的验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20157664/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com