You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are 2 simple models. Cat and Dog. Cat has a name and Dog has a name and cat_id.
Cat has an after_update callback that will update all its dogs.
Dog has an after_commit callback that will print dog barks on destroy.
The dog callback will not fire if they got called in the same transaction because ActiveRecord::ConnectionAdapters::Transaction#commit_records method will do uniq on records. Sometimes, same record could get pushed into the transaction records array with different state multiple times, like one destroyed and one persisted.
# frozen_string_literal: true
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "activerecord", "5.2.1"
gem "sqlite3"
gem "pry"
end
require "active_record"
require "minitest/autorun"
require "logger"
require "pry"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :cats do |t|
t.string :name
t.timestamps
end
create_table :dogs do |t|
t.string :name
t.integer :cat_id
t.timestamps
end
end
class Cat < ActiveRecord::Base
has_many :dogs
after_update :update_dogs
def update_name(name)
self.name = name
save!
end
def update_dogs
dogs.each do |dog|
dog.name = 'new dog'
dog.save!
end
end
end
class Dog < ActiveRecord::Base
belongs_to :cat
after_commit :bark, on: :destroy
def bark
puts "dog barks"
end
end
class BugTest < Minitest::Test
def test_stuff
Cat.create(:name => 'cat')
dog = Dog.new(:name => 'dog_2')
dog.cat = Cat.last
dog.save
puts'----------------------------------'
puts'Dog should bark in this example: '
puts
Dog.transaction do
dog = Dog.last
cat = dog.cat
cat.update_name('cat 2')
dog.destroy
end
end
end
Expected behavior
after_destroy_commit callback bark should fire after dog.destroy in the transaction above.
D, [2018-12-07T10:56:59.999822 #33390] DEBUG -- : (0.0ms) begin transaction
D, [2018-12-07T10:57:00.000744 #33390] DEBUG -- : Dog Load (0.2ms) SELECT "dogs".* FROM "dogs" ORDER BY "dogs"."id" DESC LIMIT ? [["LIMIT", 1]]
D, [2018-12-07T10:57:00.008017 #33390] DEBUG -- : Cat Load (0.1ms) SELECT "cats".* FROM "cats" WHERE "cats"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
D, [2018-12-07T10:57:00.009899 #33390] DEBUG -- : Cat Update (0.1ms) UPDATE "cats" SET "name" = ?, "updated_at" = ? WHERE "cats"."id" = ? [["name", "cat 2"], ["updated_at", "2018-12-07 15:57:00.008533"], ["id", 1]]
D, [2018-12-07T10:57:00.015809 #33390] DEBUG -- : Dog Load (0.1ms) SELECT "dogs".* FROM "dogs" WHERE "dogs"."cat_id" = ? [["cat_id", 1]]
D, [2018-12-07T10:57:00.017123 #33390] DEBUG -- : Dog Update (0.2ms) UPDATE "dogs" SET "name" = ?, "updated_at" = ? WHERE "dogs"."id" = ? [["name", "new dog"], ["updated_at", "2018-12-07 15:57:00.016259"], ["id", 1]]
D, [2018-12-07T10:57:00.018520 #33390] DEBUG -- : Dog Destroy (0.2ms) DELETE FROM "dogs" WHERE "dogs"."id" = ? [["id", 1]]
D, [2018-12-07T10:57:00.018953 #33390] DEBUG -- : (0.0ms) commit transaction
dog barks
Actual behavior
after_destroy_commit callback bark does not fire in the example
D, [2018-12-07T10:56:59.999822 #33390] DEBUG -- : (0.0ms) begin transaction
D, [2018-12-07T10:57:00.000744 #33390] DEBUG -- : Dog Load (0.2ms) SELECT "dogs".* FROM "dogs" ORDER BY "dogs"."id" DESC LIMIT ? [["LIMIT", 1]]
D, [2018-12-07T10:57:00.008017 #33390] DEBUG -- : Cat Load (0.1ms) SELECT "cats".* FROM "cats" WHERE "cats"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
D, [2018-12-07T10:57:00.009899 #33390] DEBUG -- : Cat Update (0.1ms) UPDATE "cats" SET "name" = ?, "updated_at" = ? WHERE "cats"."id" = ? [["name", "cat 2"], ["updated_at", "2018-12-07 15:57:00.008533"], ["id", 1]]
D, [2018-12-07T10:57:00.015809 #33390] DEBUG -- : Dog Load (0.1ms) SELECT "dogs".* FROM "dogs" WHERE "dogs"."cat_id" = ? [["cat_id", 1]]
D, [2018-12-07T10:57:00.017123 #33390] DEBUG -- : Dog Update (0.2ms) UPDATE "dogs" SET "name" = ?, "updated_at" = ? WHERE "dogs"."id" = ? [["name", "new dog"], ["updated_at", "2018-12-07 15:57:00.016259"], ["id", 1]]
D, [2018-12-07T10:57:00.018520 #33390] DEBUG -- : Dog Destroy (0.2ms) DELETE FROM "dogs" WHERE "dogs"."id" = ? [["id", 1]]
D, [2018-12-07T10:57:00.018953 #33390] DEBUG -- : (0.0ms) commit transaction
System configuration
Rails version: 5.2.1
Ruby version: 2.2.4
The text was updated successfully, but these errors were encountered:
marunbai
changed the title
after_commit callback does not fire if the same record got updated with a different reference in the same transaction
after_commit callback does not fire if the same record got updated with a different reference in the same transaction block
Dec 6, 2018
This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the 5-2-stable branch or on master, please reply with all of the information you have about it in order to keep the issue open.
Thank you for all your contributions.
Steps to reproduce
Here is the set up:
There are 2 simple models. Cat and Dog. Cat has a name and Dog has a name and cat_id.
Cat has an after_update callback that will update all its dogs.
Dog has an after_commit callback that will print
dog barks
on destroy.The dog callback will not fire if they got called in the same transaction because
ActiveRecord::ConnectionAdapters::Transaction#commit_records
method will do uniq on records. Sometimes, same record could get pushed into the transactionrecords
array with different state multiple times, like one destroyed and one persisted.Expected behavior
after_destroy_commit callback
bark
should fire afterdog.destroy
in the transaction above.Actual behavior
after_destroy_commit callback
bark
does not fire in the exampleSystem configuration
Rails version: 5.2.1
Ruby version: 2.2.4
The text was updated successfully, but these errors were encountered: