After_commit with `prepend` and new Rails 7.1 defaults

I am working on updating an app to use the new Rails 7.1 default run_after_transaction_callbacks_in_order_defined = true.

Prior to Rails 7.1, after_commit callbacks ran in reverse order they were defined.

However, you could add prepend: true to a later after_commit callback, to get it to be added to the beginning of the list… where it would run last. This certainly is confusing, we can see why it was changed.

But just note: you could use prepend: true to alter the chain insertion point of an after_commit callback, the same as you can for most (all?) other lifecycle after_ callbacks.

After Rails 7.1, with run_after_transaction_callbacks_in_order_defined = true, after_commit callbacks are… run in the order they are defined.

But it seems we can no longer use prepend: true to alter the insertion order of an after_commit call back.

# Rails 7.1 with run_after_transaction_callbacks_in_order_defined = true

   after_commit :one
   after_commit :two
   # one will run first, then two

#vs:
  after_commit :one
  after_commit :two, prepend: true
  # NO CHANGE, one will run first, then two

Is this intentional? A bug? Just how it is?

When updating my app to use the new default order, there are times – just as there were before – when I want to use prepend: true to change a callback’s insertion order.

One of my use-cases has to do with after_commit set in a subclass and superclass (with STI)… so there is no good way to change the order in source code, I think.

But there is no longer any way to do that, which is causing me pain in my migration to the new default. It surprises me that prepend: true option was intentionally taken away, when other after_ callbacks still have it?

Can anyone find any reasonable workaround? I don’t think there is one?

Here is a more specific spelling out of the use case, for ActiveRecord inheritance.

class Animal < ApplicationRecord
   after_commit do
      puts "animal after_commit"
   end
end

class Cat < Animal
   after_commit do
      puts "cat after_commit"
   end
end

If you Cat.create!, in Rails 7.0 it will be in this order:

cat after_commit
animal after_commit

But you CAN reverse the order using prepend: true on the second one:

class Cat < Animal
   after_commit prepend:true do
      puts "cat after_commit"
   end
end

In Rails 7.1, with new default active_record.run_after_transaction_callbacks_in_order_defined = true, the default order is reversed:

animal after_commit
cat after_commit

But you CANNOT reverese the order with prepend:true. prepend is now an unsupported no-op on after_commit.

I have code involving super-classes and sub-classes like this, where I need to control the order of execution. In Rails 7.0 I could. But with Rails 7.1 new defaults, the order is reversed and I cannot use prepend to alter it anymore.

This is giving me a problem in upgrading to to Rails 7.1 new defaults. I have lost ability to control the order of execution of after_commit callbacks.

I would like to think this is a bug… but I’m going to guess I’m going to be told prepend was always an unsupported feature and/or is no longer supported.

Can anyone think of any workarounds?