如何查找ActiveRecord ROLLBACK的原因

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

在日志中我看到了

ROLLBACK
,但没有记录任何异常。有没有办法找出导致回滚的原因?

以下是日志摘录:

  Phone Load (0.4ms)  SELECT "phones".* FROM "phones" WHERE "phones"."id" = $1 LIMIT 1  [["id", 980190963]]
   (0.2ms)  BEGIN
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."phone_id" = 980190963 LIMIT 1
   (0.2ms)  ROLLBACK
  Phone Load (0.4ms)  SELECT "phones".* FROM "phones" WHERE "phones"."id" = $1 LIMIT 1  [["id", 980190963]]
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."phone_id" = 980190963 LIMIT 1
ruby-on-rails activerecord
5个回答
113
投票

用 BANG '!' 保存记录所以它会产生运行时错误,你知道它发生在哪里


52
投票

一种方法是手动将信息写入日志。从您的控制器尝试类似的操作:

Rails.logger.info(@your_object.errors.inspect) 

这应该输出所有失败的验证的内容。


24
投票

1) 禁用 before_create、before_save、before_update 并检查它保存当天的位置

2) 如果回滚是由这些方法之一引起的,请在您不打算回滚时检查这些方法是否返回 true。

例如,如果您为布尔字段设置默认值以避免 nil,您可能会这样做

def set_defaults_before_create
  self.my_boolean_field ||= false
end

在此示例中,方法 set_defaults_before_create 始终返回 false ,从而回滚您的事务。所以重构它以返回true

def set_defaults_before_create
  self.my_boolean_field ||= false
  true
end

10
投票

我想出的3种方法(1种失败)是

  1. 在所有相关的保存、验证方法上使用活动记录的观察者

  2. 打开活动记录并在触发 ROLLBACK 的位置放置调试器语句,然后运行

    caller
    来查明触发错误的代码。

  3. 失败:覆盖活动记录方法并在异常时暂停。如果我记得这个方法不会捕获任何异常,因为保存方法被包装在事务中。

注意:仅当模式不是 Rails.env.Production? 时才启用。在 Rails 3.2.13 上测试,使用 ruby 1.9.3。

  1. 观察者:http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#observers

     class ActiveRecordObserver < ActiveRecord::Observer
    
         observe "ActiveRecord::Base"
    
         def after_validation(model)
             debugger if model.errors.messages.any?
             Rails.logger.error "after validation"
         end
         def before_update(model)
             debugger if !model.valid?
             Rails.logger.error "before update"
         end
         def after_update(model)
             debugger if !model.valid?
             Rails.logger.error "after update"
         end
         def before_save(model)
    
             debugger if model.errors.messages.any?
             Rails.logger.error "#{model}"
             Rails.logger.error "before save"
         end
         def after_save(model)
             debugger if model.errors.messages.any?
             Rails.logger.error "after save"
         end
     end
    

    注意:要在最新的 Rails 版本(从 v.4 到最新的 v.6)中使用 Observers,您需要将

    gem 'rails-observers'
    捆绑在 Gemfile 中(最好包含在 :development 和 :test 组中),将
    app/observers/active_record_observer.rb
    下的类,并通过放置(或添加)以下行来在当前环境配置文件(例如
    config/environments/development.rb
    )中注册观察者:
    config.active_record.observers = [:active_record_observer]

  2. 在执行回滚时放置调试器语句。 https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L231

    运行

    cd bundle show activerecord
    找到gem文件夹。

    # /Users/<user>/.rvm/gems/ruby-1.9.3-<env>/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract/database_statements.rb
    
        196              transaction_open = false
        197              decrement_open_transactions
        198              if open_transactions == 0
        199                rollback_db_transaction
        200                debugger
     => 201                rollback_transaction_records(true)
        202              else
        203                rollback_to_savepoint
        204                debugger
        205                rollback_transaction_records(false)
    

    当 Rails 服务器或控制台遇到断点时,输入

    caller
    即可获取回溯。

  3. 在开发模式下覆盖 AR。 TODO:仅在 !Rails.env.Production?

    时覆盖

    把这个放进去

    app/config/initializers/active_record_or_any_file_name.rb

     ActiveRecord::Base.class_eval do
         alias_method :old_save, :save
         alias_method :old_save!, :save!
         def save(*args)
             begin
                 puts "#{self} save"
                 Rails.logger.info "#{self} save"
                 old_save(*args)
             rescue Exception => e
                 debugger
                 puts e
             end
         end
         def save!(*args)
             begin
                 Rails.logger.info "#{self} save!"
                 puts "#{self} save!"
                 old_save!(*args)
             rescue Exception => e
                 debugger
                 puts e
             end
         end
     end
    

0
投票

在我的例子中,

has_many
关联是用
dependent: :restrict_with_error
而不是
dependent: :destroy
定义的。它是在一个问题中定义的,所以我没有立即看到它。不管怎样,如果 Rails 能告诉我们是什么原因导致回滚发生那就太好了:-)

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