【问题标题】:after_commit callback is being called several timesafter_commit 回调被多次调用
【发布时间】:2012-01-05 22:00:57
【问题描述】:

更新: 对 update_attributes 的调用是否会获得它自己的事务?

我查看了this 问题,除了这个问题之外,我决定使用 after_commit 作为正确的钩子。问题是它被多次(恰好三次)调用。代码解释起来有点复杂,但基本上有一个profile模型有

include Traits::Blobs::Holder

在 holder.rb 我有:

  module ClassMethods

    def belongs_to_blob(name, options = {})
      clazz = options[:class_name] ? options[:class_name].constantize : Blob
      foreign_key = options[:foreign_key] || :"#{name}_id"

      define_method "save_#{name}" do
        blob = self.send(name)
        if self.errors.any? && blob && blob.valid?
          after_transaction do
            blob.save!
            #self[foreign_key] = blob.id
            #save resume anyway
            self.update_attribute(foreign_key, blob.id)
          end
        end
      end
      after_validation "save_#{name}"

      belongs_to name, options

      accepts_nested_attributes_for name
    end

  end 

终于在 profile.rb 中我有了:

after_commit :send_messages_after_registration!

protected

def send_messages_after_registration!
  Rails.logger.debug("ENTERED : send_messages_after_registration " + self.owner.email.to_s)
  if self.completed?
    Rails.logger.debug("completed? is true " + self.owner.email.to_s)
    JobSeekerNotifier.webinar_notification(self.owner.id).deliver
    Resque.enqueue_in(48.hours, TrackReminderWorker, self.owner.id)
  end
end

该方法似乎输入了 3 次。几天来我一直在尝试解决这个问题,因此您可以提供任何指导,我们将不胜感激。

控制器代码:

def create
  @user = Customer.new(params[:customer].merge(
    :source => cookies[:source]
  ))
  @user.require_password = true

  respond_to do |f|
    if @user.save
      promote_provisional_user(@user)  if cookies[:provisional_user_id]

      @user.profile.update_attributes(:firsttime => true, :last_job_title => params[:job_title]) unless params[:job_title].blank?

      if params[:resume]
        @user.profile.firsttime = true
        @user.profile.build_resume(:file => params[:resume])
        @user.profile.resume.save
        @user.profile.save
      end
    ...
end

【问题讨论】:

  • 个人资料是否调用belongs_to_blob?
  • 调用代码是什么样的?
  • 用控制器代码更新了我的问题
  • 是的。 profile 有这个关联:belongs_to_blob :resume
  • 这是一个很好的问题:什么时候调用像 belongs_to_blob 这样的关联方法来处理事务回调?

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


【解决方案1】:

所以它发生了 3 次,因为配置文件被保存了 3 次:一次是在保存用户时(我假设是 User accepts_nested_attributes_for :profile,一次是在您调用 update_attributes(:first_time => true,...) 时,一次是在您调用 if params[:resume] 块中的 save 时. 每次保存都会创建一个新事务(除非一个已经在进行中)你最终会多次调用after_commit

after_commit 确实采用 :on 选项(可以采用值 :create:update:destroy),以便您可以将其限制为新记录。这显然会在第一次保存时触发,因此您将无法看到个人资料的简历等等。

您还可以将所有这些更新包装在单个事务中,在这种情况下,after_commit 只会被调用一次,无论通过执行类似操作在事务中发生多少次保存

User.transaction do
  if @user.save
    ...
  end
end

如果引发异常,事务将回滚(如果您想退出,可以引发 ActiveRecord::Rollback

【讨论】:

  • 您能否解释一下我如何wrap the entirety of those updates in a single transaction 这听起来像是所需的行为。感谢您的帮助!
  • 这是个好主意,但它似乎仍然发送两封电子邮件。
  • 那么你可能会在别处调用 save 。记录调用堆栈(调用调用者)或在回调中放置断点以查看从何处调用您
猜你喜欢
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 2018-06-02
  • 2015-04-23
  • 1970-01-01
相关资源
最近更新 更多