在AASM中停止来自后置回调的事件,而不引发异常。

huangapple go评论60阅读模式
英文:

Stopping event in AASM from after callback without raising exception

问题

aasm : :status, whiny_transitions: false do
  状态 :requested, 初始: true
  状态 :approved

  事件 :approve, 之后: :after_approve do
    过渡 : :requested, : :approved
  end
end

def after_approve
  抛出 "这是一个测试"
end

鉴于上述内容,我希望能够调用 obj.approve! 并且仍然让它返回 true 或 false,以便我可以在模型中处理异常,向对象添加错误并在控制器中处理它。

我尝试过返回 false,使用错误处理程序等,但似乎没有办法在之后的回调中停止事件而不抛出异常,也没有办法捕获异常并返回 false(在我找到的情况下)。

作为一种变通方法,我不得不创建一个新的方法来包装对 approve! 的调用:

  def approve_with_errors
    approve!
  rescue StandardError => e
    错误.add(:base, "错误: #{e}")
    false
  end

在 aasm 中有没有办法实现这一点,而无需添加这些包装器?

顺便说一下,在 Rails 中的之后回调中,您需要抛出 ActiveRecord::RecordInvalid, self 并且回调链将会被中止,但是异常不会传递到堆栈上。在 before_ 回调中执行相同操作,您可以使用 throw(:abort)GitHub 上的 AASM 问题

英文:
aasm column: :status, whiny_transitions: false do
  state :requested, initial: true
  state :approved

  event :approve, after: :after_approve do
    transitions from: :requested, to: :approved
  end
end

def after_approve
  raise "This is a test"
end

Given the above I want to be able to call obj.approve! and still have it return true or false so I can handle the exceptions in the model, add errors to the object and handle it in the controller.

I have tried returning false, error handlers etc but it seems there is no way to stop the event from the after callback without raising, nor is there any way to catch the exception handle it and return false (that I can find).

As a workaround I've had to create a new method which wraps the call to approve!

  def approve_with_errors
    approve!
  rescue StandardError => e
    errors.add(:base, "Error: #{e}")
    false
  end

Is there any way to achieve this in aasm without adding these wrappers?

As a side note, on Rails in after callbacks you need to raise ActiveRecord::RecordInvalid, self and the callback chain will be aborted but the exception is not passed up the stack. To do the same in before_ callbacks you can throw(:abort) https://github.com/rails/rails/issues/33192

I've also created an issue in AASM Github

答案1

得分: 1

如果引发 ActiveRecord::Rollback(而不是 RecordInvalid),那么Rails在回滚数据库后不会将该异常传播到链上。所以...

    event :approve, after: :after_approve do
      transitions from: :requested, to: :approved

      error do |e|
        errors.add :base, "错误:#{e.message}"
        raise ActiveRecord::Rollback
      end
    end

# ...

> obj.approve!
  ...
  TRANSACTION0.3毫秒)ROLLBACK
nil
> obj.errors
#<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=错误:这是一个测试,options={}>]>
英文:

If you raise ActiveRecord::Rollback (not RecordInvalid) then Rails won't propagate that exception up the chain after rolling the DB back. So...

    event :approve, after: :after_approve do
      transitions from: :requested, to: :approved

      error do |e|
        errors.add :base, &quot;Error: #{e.message}&quot;
        raise ActiveRecord::Rollback
      end
    end

# ...

&gt; obj.approve!
  ...
  TRANSACTION (0.3ms)  ROLLBACK
nil
&gt; obj.errors
#&lt;ActiveModel::Errors [#&lt;ActiveModel::Error attribute=base, type=Error: This is a test, options={}&gt;]&gt;

huangapple
  • 本文由 发表于 2023年7月20日 17:03:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定