为什么在嵌套关联中抛出中止会引发“无法销毁记录”异常?

问题描述 投票:0回答:1

在销毁相机之前,我需要验证是否有任何CameraVectors与任何MonitoredPlace相关联。

相机的型号

class Camera < ApplicationRecord
  belongs_to :location
  has_many :camera_vectors, inverse_of: :camera, dependent: :destroy

  validates :description, :device_serial, :device_name, 
    :device_type, :device_api_url, :device_user, :device_password,
    presence: true

  accepts_nested_attributes_for :camera_vectors, allow_destroy: true
end

CameraVector的模型

class CameraVector < ApplicationRecord
  belongs_to :camera, inverse_of: :camera_vectors
  belongs_to :monitored_place, optional: true

  validates :description, presence: true
  validates :position, numericality: { greater_than_or_equal_to: 0 }, presence: true

  before_destroy :has_monitored_place?

  private

  def has_monitored_place?
    if monitored_place.present?
      errors.add(:base, "cannot delete")
      throw :abort
    end
  end
end

MonitoredPlace的模型

class MonitoredPlace < ApplicationRecord
  belongs_to :location
  belongs_to :place_type
  has_many :camera_vectors

  validates :place_name, presence: true
  validates :place_type_id, uniqueness: { scope: :location_id }, presence: true

  scope :enabled, -> { where.not(enabled_on: nil).where(disabled_on: nil) }
end

因为每当我尝试更新或销毁摄像机时的accepts_nested_attributes_for,这个嵌套字段都会被发送为params

"camera_vectors_attributes"=>{"0"=>{"description"=>"A", "position"=>"1", "_destroy"=>"1", "id"=>"47"}}

我想如果我在模型CameraVector中写了一个回调before_destroy我可以验证它,但如果验证发生,它会在控制器中引发ActiveRecord :: RecordNotDestroyed。

if @camera.destroy(camera_params)
  redirect_to(action: :index, notice: t(".success"))
else
  render :index
end
ruby-on-rails ruby-on-rails-5
1个回答
0
投票

你可以在api documentation阅读

ActiveRecord::RecordNotDestroyed

由ActiveRecord :: Base#destroy引发!当对#destroy的调用返回false时。

这是结果

before_destroy :has_monitored_place?

调用方法并返回false

def has_monitored_place?
 if monitored_place.present?
   errors.add(:base, "cannot delete")
   throw :abort
 end
end

要改变这种行为,请实现类似于api中描述的逻辑

begin
  complex_operation_that_internally_calls_destroy!
rescue ActiveRecord::RecordNotDestroyed => invalid
  puts invalid.record.errors
end

或阅读

How do I 'validate' on destroy in rails

© www.soinside.com 2019 - 2024. All rights reserved.