Rails 5中已签署TimeWorked及其关联资源的删除阻止问题
解决Rails中已签署模型及其关联资源无法同时阻止删除的问题
这个问题的核心是Rails处理dependent: :destroy的时机和回调执行顺序导致的——当你尝试销毁TimeWorked时,Rails会先触发关联TimeWorkedEvent的销毁操作,再执行TimeWorked自身的before_destroy回调。这就导致即便你的TimeWorked销毁被阻止,关联的TimeWorkedEvent已经被删掉了。
下面是完整的解决方案,分两步确保主模型和关联模型都无法被修改/删除:
1. 在关联模型TimeWorkedEvent中添加阻止销毁/更新的回调
因为Rails会优先处理关联的销毁,所以我们需要在TimeWorkedEvent层面直接拦截操作,确保关联的TimeWorked已签署时,无法销毁或修改该关联:
class TimeWorkedEvent < ApplicationRecord belongs_to :event belongs_to :time_worked validates_presence_of :event validates_presence_of :time_worked validates_uniqueness_of :time_worked_id # 阻止销毁已签署TimeWorked的关联事件 before_destroy do if time_worked.signed_exist? errors.add(:base, "无法销毁已签署工时记录关联的事件") throw(:abort) end end # 阻止更新已签署TimeWorked的关联事件 before_update do if time_worked.signed_exist? errors.add(:base, "无法修改已签署工时记录关联的事件") throw(:abort) end end end
2. 完善TimeWorked模型的回调逻辑
确保TimeWorked自身的更新和销毁操作被正确拦截,同时通过prepend: true保证回调优先执行,避免关联处理先于拦截逻辑:
class TimeWorked < ApplicationRecord has_one :time_worked_event, dependent: :destroy has_one :event, through: :time_worked_event accepts_nested_attributes_for :time_worked_event, reject_if: proc {|att| att[:event_id].blank?} # 优先执行拦截回调,确保在关联处理前触发 before_destroy :prevent_modification_of_signed_records, prepend: true before_update :prevent_modification_of_signed_records, prepend: true private def prevent_modification_of_signed_records if signed_exist? errors.add(:signed, "无法修改或销毁已签署的工时记录") throw(:abort) end end # 假设你的签署状态判断逻辑是这样的,根据实际业务调整 def signed_exist? signed? # 示例:通过boolean字段`signed`判断是否已签署 end end
额外说明:嵌套属性的处理
因为你使用了accepts_nested_attributes_for,当用户尝试通过TimeWorked的表单修改或删除TimeWorkedEvent时,上述的TimeWorkedEvent回调会自动拦截这些操作,确保已签署的记录无法被篡改。
这样调整后,无论是直接操作TimeWorked还是其关联的TimeWorkedEvent,只要TimeWorked已签署,所有修改和销毁操作都会被阻止,且不会出现关联被意外删除的情况。
内容的提问来源于stack exchange,提问作者Alexis Delahaye
相关产品推荐
相关产品推荐

