如何挽救模型交易并向用户显示错误?

NoD*_*ame 27 ruby activerecord transactions ruby-on-rails

因此,假设您有2个模型,人员和地址,每人只有一个地址可以标记为"主要".因此,如果我想更改一个人的主要地址,我需要使用一个事务,将新的标记标记为主要标记并取消标记旧标记.据我所知,在控制器中使用事务并不好,所以我在模型中有一个特殊的方法,这就是我所拥有的:

AddressesController < ApplicationController
 def update
  @new_address = Address.find(params[:id])
  @old_address = Address.find(params[:id2])
  @new_address.exchange_status_with(@old_address)       
 end
end
Run Code Online (Sandbox Code Playgroud)

模型:

class Address < ActiveRecord::Base
  def exchange_status_with(address)
    ActiveRecord::Base.transaction do
     self.save!
     address.save!
    end     
  end
end
Run Code Online (Sandbox Code Playgroud)

所以问题是,如果模型方法中的事务失败,我需要解救它并通知用户错误,我该怎么做?有没有办法让这个模型方法返回true或false,具体取决于事务是否成功,就像save方法一样?

我可能可以将该事务放在控制器中并在救援部分中呈现错误消息,但我猜它不对或者我可以将该方法放在回调中,但想象有一些原因我不能这样做,是什么替代方案?

PS不要注意查找带有params id和id2的实例,只是随机的事情来表明我有2个实例

apn*_*ing 53

def exchange_status_with(address)
  ActiveRecord::Base.transaction do
   self.save!
   address.save!
  end
rescue ActiveRecord::RecordInvalid => exception
  # do something with exception here
end
Run Code Online (Sandbox Code Playgroud)

仅供参考,例外情况如下:

#<ActiveRecord::RecordInvalid: Validation failed: Email can't be blank>
Run Code Online (Sandbox Code Playgroud)

和:

exception.message
# => "Validation failed: Email can't be blank"
Run Code Online (Sandbox Code Playgroud)

旁注,你可以self.save!改为save!


如果要保持活动模型错误,请替代解决方案:

class MyCustomErrorClass < StandardError; end

def exchange_status_with(address)
  ActiveRecord::Base.transaction do
   raise MyCustomErrorClass unless self.save
   raise MyCustomErrorClass unless address.save
  end
rescue MyCustomErrorClass
  # here you have to check self.errors OR address.errors
end
Run Code Online (Sandbox Code Playgroud)

  • 如果有人感兴趣,我已经创建了 TIL 注释来总结基于这个 SO 问题的救援交易时的不同做法和做法:https://blog.eq8.eu/til/rollback-rails-transaction-and-rescue-显示错误.html (2认同)
  • @equivalent8,似乎你的链接已损坏,它最后有“-it”,但不应该:https://blog.eq8.eu/til/rollback-rails-transaction-and-rescue-error-to- display.html 另外,很棒的文章,谢谢! (2认同)