Skip to content

after_commit order inconsistent with other callbacks  #20911

Closed
@odedniv

Description

@odedniv

It seems that the commit callbacks (defined in https://github.com/rails/rails/blob/master/activerecord/lib/active_record/transactions.rb#L230) is defined differently from the rest of the callbacks (defined in https://github.com/rails/rails/blob/master/activemodel/lib/active_model/callbacks.rb#L103).

I experienced this difference in the order after_commit is executed. It seems that after_* callbacks are executed in reverse order, and after_commit doesn't handle this:

class M < ActiveRecord::Base
  before_create :a
  before_create :b
  after_create :c
  after_create :d
  after_commit :e
  after_commit :f

  def a; puts 'a'; end
  def b; puts 'b'; end
  def c; puts 'c'; end
  def d; puts 'd'; end
  def e; puts 'e'; end
  def f; puts 'f'; end
end

M._create_callbacks.select { |c| c.kind == :before }.map(&:filter)
=> [:a, :b]
M._create_callbacks.select { |c| c.kind == :after }.map(&:filter)
=> [:d, :c] # Weird behavior in after_* callbacks
M._commit_callbacks.select { |c| c.kind == :after }.map(&:filter)
=> [:e, :f]

M.create
=> a
=> b
=> c
=> d
=> f # The result of after_commit not handling the weird behavior
=> e

after_* callbacks add a default (actually, they override) prepend: true to the options to resolve this (see here https://github.com/rails/rails/blob/master/activemodel/lib/active_model/callbacks.rb#L139), while after_commit doesn't, thus the inconsistency.

The culprit seems to be the reverse execution in after_* callbacks and not really after_commit, I would say the code in after_* is just a patch to solve this. This patch actually prevents using the :prepend option in the after_* callbacks.

I would also change the definition of the transactions callbacks to use the same logic of the rest of the callbacks to prevent inconsistencies in the future.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions