Rails after_save 回调被多次调用的问题

dudu_zzzz · 2015年11月09日 · 最后由 sennmac 回复于 2015年11月13日 · 2202 次阅读

写了一个 Reindex module 代码如下,功能就是在 ActiveRecord 对象 save 时,异步创建索引

module Reindex
  def async_reindex
    AsyncIndexJob.perform_later(self.class.to_s, self.id)
  end

  def self.included(base)
    base.class_eval do
       base.send :after_save ,:async_reindex
    end
  end
end

测试代码

require 'rails_helper'

RSpec.describe AsyncIndexJob, type: :job do
  include ActiveJob::TestHelper
    describe "AsyncIndexJob" do
      it "should enqueue" do
        group = Group.create(……)
        expect(enqueued_jobs.size).to eq(1)
    end
  end
end

但是结果非常奇怪,queue 的 size 是 3,也就是 after_save 被调用了 3 次,为什么会这样呢?

Failures:

  1) AsyncIndexJob AsyncIndexJob should enqueue
     Failure/Error: expect(enqueued_jobs.size).to eq(1)

       expected: 1
            got: 3

补充一下 如果把 base.send :after_save ,:async_reindex 改成 base.send :after_create ,:async_reindex,那么 queue 的 size 是 2, 再改成 base.send :after_commit ,:async_reindex,queue 的 size 是 0,我懵的不行。

发现是 active_record 的问题 坑! 在新建我的 Group Model 时,执行了三次 save 操作,第一次插入一个 group,然后插入一个 GroupAccount,然后更新 group 的值,加入了 member_count。

··· SQL (8.6ms) INSERT INTO groups (type, name, description, logo, creator_id, status, formal_type, talk_count, subject_count, recommend_count, posts_count, active_member_count, games_count, subs_count, created_at, updated_at) VALUES ('Groups::GameGroup', 'funn', 'hi', 'logo', 262763, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2015-11-08 23:31:24', '2015-11-08 23:31:24') SQL (1.7ms) INSERT INTO groups_accounts (group_id, talk_count, subject_count, recommend_count, post_count, account_id, created_at, updated_at) VALUES (2086, 0, 0, 0, 0, 262763, '2015-11-08 23:31:24', '2015-11-08 23:31:24') SQL (0.9ms) UPDATE groups SET type = 'Groups::GameGroup', name = 'funn', description = 'hi', logo = 'logo', creator_id = 262763, status = 0, formal_type = 0, talk_count = 0, subject_count = 0, recommend_count = 0, posts_count = 0, active_member_count = 0, subs_count = 0, created_at = '2015-11-08 23:31:24', updated_at = '2015-11-08 23:31:24', id = 2086, member_count = 1 WHERE groups.id = 2086 ···

你扩展了 ActiveRecord::Base,然后你跟我说是 ActiveRecord 的锅,ActiveRecord 表示不服。 来吃了这碗教程:http://guides.rubyonrails.org/active_record_callbacks.html

需要 登录 后方可回复, 如果你还没有账号请 注册新账号