我有以下行动:
# DELETE /my_controller/ids[]
def destroy_multiple
ids = params[:ids]
ActiveRecord::Base.transaction do
begin
SomeModel.where(id: ids).destroy_all
head :no_content
end
rescue => e
p "e #{e.inspect}" # Never called
end
您可能已经注意到,它负责删除许多记录,并且有效...
some_model.rb :
before_destroy :check_default_item
private
def check_default_item
return unless default_item?
errors.add(:base, 'Cannot delete record because it is a default item')
p "errors #{errors.inspect}" # I can see the errors
throw(:abort)
end
假设我有以下记录:
[
{ id: 1, default_item: true },
{ id: 2, default_item: true },
{ id: 3, default_item: true }
]
如果我发送这样的请求:
my_url/destroy_multiple?ids[]=3&ids[]=2&ids[]=1
我可以看到终端中的错误,如下所示:
errors #<ActiveModel::Errors:0x007fdb88364050 @base=#<SomeModel id: 3, default_item: true, created_at: "2017-08-06 18:33:03", updated_at: "2017-08-06 18:33:03">, @messages={:base=>["Cannot delete record because it is a default item"]}, @details={:base=>[{:error=>"Cannot delete record because it is a default item"}]}>
...但它给了我204响应,而不是422。
由于我正在调用throw(:abort)
,为什么它不会抛出错误/异常?它甚至没有去rescue
。
请注意,如果我尝试删除这样的单个记录:
@item.destroy!
它有效,我收到&#34;无法删除记录,因为它是默认项目&#34;消息。
答案 0 :(得分:1)
destroy_all
方法只是循环播放并在每条记录上调用destroy
,而不是destroy!
:
def destroy_all records.each(&:destroy).tap { reset } end
如果destroy
失败,destroy!
只会返回false
(来自throw(:abort)
:
如果before_destroy回调抛出:abort则取消操作并且destroy返回false。
这意味着如果您想要引发错误(就像使用https://codepen.io/anon/pen/OjmGMy?editors=0000时那样),您将需要使用自定义方法(没有destroy_all!
)。
由于destroy_all
的正文相对简单,您可以在代码中复制它:
SomeModel.where(id: ids).each(&:destroy!)
应该这样做,如果你没有尝试重用任何关系(因此不需要它reset
)。