【发布时间】:2016-06-14 19:50:35
【问题描述】:
在特定条件下,有没有办法在活动记录的 before_destroy 回调中取消对象的销毁?谢谢
【问题讨论】:
标签: ruby-on-rails activerecord
在特定条件下,有没有办法在活动记录的 before_destroy 回调中取消对象的销毁?谢谢
【问题讨论】:
标签: ruby-on-rails activerecord
你应该返回false。
"取消回调
如果 before_* 回调抛出 :abort,所有后面的回调和相关的操作都会被取消。"
"取消回调
如果 before_* 回调返回 false,则所有后面的回调和相关操作都将被取消。回调通常按照定义的顺序运行,但定义为模型上的方法的回调除外,这些方法最后调用。”
【讨论】:
throw(:abort) 以防止记录删除。见this comment
由于没有一个给出的答案真正解决了问题,但上面的评论告诉了它 - 这里是一个答案的形式,以便于找到:
在 rails 5 中,而不是
before_destroy do
if self.some_condition?
return false
end
end
使用
before_destroy do
if self.some_condition?
throw(:abort)
end
end
确保没有执行销毁。
感谢RFVoltolini's comment - 这拯救了我的一天!
【讨论】:
Rails 在事务中包装保存和销毁,因此回调中的 raise 可以工作:
class Post < ActiveRecord::Base
before_destroy :saveable?
def saveable?
if true
raise "Destroy aborted; you can't do that!"
end
end
end
将true 替换为您的情况。
这是精简的控制台输出:
[1] pry(main)> Post.first.id
=> 1
[2] pry(main)> Post.first.destroy
RuntimeError: Destroy aborted; you can't do that!
[3] pry(main)> Post.first.id
=> 1
【讨论】:
before_* 回调,所以raise 或false 都可以。 raise 的好处是您将获得可以在日志中跟踪的明确消息,而不是 destroy 悄悄地没有发生。选择哪一个取决于您的失败案例的意外程度。
raise :abort。你不妨现在就开始。
raise :abort 对我不起作用。我认为它必须是throw :abort
返回false 是正确的方法:
before_destroy do
if self.some_condition?
return false
end
end
您可以在6 Halting Execution 点下查看文档。
http://guides.rubyonrails.org/active_record_callbacks.html
【讨论】:
您还可以覆盖#destroy 方法:
def destroy
study_assignments.empty? ? super : raise("can not be destroyed")
end
【讨论】: