Rails before_save方法无法执行'else'块

时间:2013-07-06 22:43:19

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

这是我的before_save方法:

  before_save :check_postal

  def check_postal
    first_three = self.postal_code[0..2]
    first_three.downcase!

    postal = Postal.find_by_postal_code(first_three)

    if postal
      self.zone_id = postal.zone_id
    else
      PostalError.create(postal_code: self.postal_code)
      return false
    end
  end

self.zone_id = postal.zone_id时一切正常,但在else语句中,我的PostalError.create(postal_code: self.postal_code)不会将记录保存到数据库中。

我知道它与return false语句有关,因为当我删除它时,它会保存得很好 - 但是这会使目的失败..

如何在返回false时保存新的PostalError记录以防止当前对象保存...

2 个答案:

答案 0 :(得分:4)

你说得对:问题是before_save

整个保存过程都包含在一个事务中。如果保存失败,无论是由于验证失败,还是正在回滚异常还是其他原因,都会回滚该事务。这将撤消PostalError记录的创建。

通常这是一件好事 - 这样不完整的保存不会留下碎屑

我可以想出两种方法来解决这个问题。一种是根本不在那里创建记录:一旦危险过去,使用after_rollback钩子来执行它。

另一种方法是使用不同的数据库连接创建该记录(因为事务是每个连接事物)。一种简单的方法是使用不同的线程:

Thread.new { PostalError.create(...)}.join

我将join放在那里,以便等待线程完成,而不是为您的应用添加一些您可能不期望的并发度。

答案 1 :(得分:-2)

我不知道,但我试图猜测解决方案。

else
  PostalError.create(postal_code: self.postal_code)
  self.zone_id = postal.zone_id
end