{"push_id":962900654,"size":1,"distinct_size":1,"ref":"refs/heads/after_callbacks_in_order_of_definition","head":"0dd086f459e19564b2cd6d8939093390a20b7937","before":"b417459eb15f1b3145c6534bfd66dc066b770a14","commits":[{"sha":"0dd086f459e19564b2cd6d8939093390a20b7937","author":{"email":"fa9bdd3a2d9982eccc7efdbb476d937166f0b5c2@gmail.com","name":"Piotr Jakubowski"},"message":"After callbacks in regular order and around have separate order context\n\nDifferent, and in my opinion better approach of fixing the problem\nstated in #15106. This commit changes the underlying implementation of\nall callbacks in Rails - ActiveSupport::Callbacks.\n\nExisting implementation of callbacks have 2 quirks:\n1. After callbacks are being run in reverse order\n2. Around callback completely changes the ordering context\n\nSo let's say we have following case\n\n```\nclass CallbacksOrWhat\n  include ActiveSupport::Callbacks\n\n  define_callbacks :run\n\n  set_callback :run, :before, :before_a\n  set_callback :run, :after, :after_a\n  set_callback :run, :around, :around_a\n  set_callback :run, :after, :after_b\n  set_callback :run, :after, :after_c\n  set_callback :run, :around, :around_b\n  set_callback :run, :after, :after_d\n  set_callback :run, :before, :before_b\n\n  def before_a; puts \"before a\"; end\n  def before_b; puts \"before b\"; end\n  def after_a; puts \"after a\"; end\n  def after_b; puts \"after b\"; end\n  def after_c; puts \"after c\"; end\n  def after_d; puts \"after d\"; end\n\n  def around_a\n    puts \"around before a\"\n    yield\n    puts \"around after a\"\n  end\n\n  def around_b\n    puts \"around before b\"\n    yield\n    puts \"around after b\"\n  end\n\n  def run\n    run_callbacks :run do\n      puts \"Running\"\n    end\n  end\nend\n\nCallbacksOrWhat.new.run\n```\n\nThe result would be\n\n```\nbefore a\naround before a\naround before b\nbefore b\nRunning\nafter d\naround after b\nafter c\nafter b\naround after a\nafter a\n```\n\nSo the after callbacks are actually run before the \"after\" part of the\naround filter that are defined before them and so on.\n\nThe consequences of that are following:\n1. ActiveModel and ActiveRecord sprinkle some options[:prepend] = true\n   around to get rid of the reverse ordering of after callbacks.\n2. Documentation of ActiveSupport claims:\n\n> Calls the before and around callbacks in the order they were set,\n> yields the block (if given one), and then runs the after callbacks in\n> reverse order.\n\n  But since definition of around callback kind of changes the context of\n  execution that's not exactly what's happening.\n\n3. The around this is pretty hard to grasp and it's hard to figure out\n   jus by looking at code what's the exact order of execution>\n\nI would expect something more along the lines:\n1. Run all before callbacks in order of definition\n2. Run all around callbacks as a stack that has the first defined on\n  top, last defined on almost bottom and the method the block they\n  are surrounding at the very bottom.\n3. Run all after callbacks\n\nSo something like this:\n\n```\nbefore a\nbefore b\naround before a\naround before b\nRunning\naround after b\naround after a\nafter a\nafter b\nafter c\nafter d\n```\n\nThis seems way more consistent, and frees ActiveRecord and ActiveModel\nfrom hacking prepend (which in the end makes the prepend option unusable\nfor the end user).","distinct":true,"url":"https://api.github.com/repos/piotrj/rails/commits/0dd086f459e19564b2cd6d8939093390a20b7937"}]}