activerecord-bitemporal icon indicating copy to clipboard operation
activerecord-bitemporal copied to clipboard

Remove `joinable: false`

Open wata727 opened this issue 1 year ago • 0 comments

Active Record transaction(joinable: false) is a private API and should not be used. If you use this, there is a problem with callbacks such as after_commit being invoked before the commit.

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "activerecord", "7.1.3"
  gem "activerecord-bitemporal", "5.0.0"
  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :employees, force: true do |t|
    t.integer :bitemporal_id
    t.datetime :valid_from, precision: 6
    t.datetime :valid_to, precision: 6
    t.datetime :transaction_from, precision: 6
    t.datetime :transaction_to, precision: 6
  end
end

class Employee < ActiveRecord::Base
  include ActiveRecord::Bitemporal

  after_commit -> { puts "after_commit is invoked" }
end

class BugTest < Minitest::Test
  def test_destroy
    employee = Employee.create
    employee.destroy!
  end
end
D, [2024-02-08T18:47:42.760262 #60695] DEBUG -- :   TRANSACTION (0.0ms)  begin transaction
D, [2024-02-08T18:47:42.760340 #60695] DEBUG -- :   Employee Load (0.1ms)  SELECT "employees".* FROM "employees" WHERE "employees"."transaction_from" <= ? AND "employees"."transaction_to" > ? AND "employees"."valid_from" <= ? AND "employees"."valid_to" > ? AND "employees"."bitemporal_id" = ? LIMIT ?  [["transaction_from", "2024-02-08 09:47:42.759508"], ["transaction_to", "2024-02-08 09:47:42.759508"], ["valid_from", "2024-02-08 09:47:42.759482"], ["valid_to", "2024-02-08 09:47:42.759482"], ["bitemporal_id", 1], ["LIMIT", 1]]
D, [2024-02-08T18:47:42.760660 #60695] DEBUG -- :   Employee Update (0.0ms)  UPDATE "employees" SET "transaction_to" = ? WHERE "employees"."id" = ?  [["transaction_to", "2024-02-08 09:47:42.759482"], ["id", 1]]
D, [2024-02-08T18:47:42.760870 #60695] DEBUG -- :   TRANSACTION (0.0ms)  SAVEPOINT active_record_1
D, [2024-02-08T18:47:42.760925 #60695] DEBUG -- :   Employee Create (0.1ms)  INSERT INTO "employees" ("bitemporal_id", "valid_from", "valid_to", "transaction_from", "transaction_to") VALUES (?, ?, ?, ?, ?) RETURNING "id"  [["bitemporal_id", 1], ["valid_from", "2024-02-08 09:47:42.758438"], ["valid_to", "2024-02-08 09:47:42.759482"], ["transaction_from", "2024-02-08 09:47:42.759482"], ["transaction_to", "9999-12-31 00:00:00"]]
D, [2024-02-08T18:47:42.760980 #60695] DEBUG -- :   TRANSACTION (0.0ms)  RELEASE SAVEPOINT active_record_1
after_commit is invoked
D, [2024-02-08T18:47:42.761034 #60695] DEBUG -- :   TRANSACTION (0.0ms)  commit transaction

See also https://github.com/rails/rails/issues/39912 https://github.com/rails/rails/issues/46182

By removing joinable: false, the callback will be executed correctly after the commit.

D, [2024-02-08T18:48:40.464346 #60711] DEBUG -- :   TRANSACTION (0.0ms)  begin transaction
D, [2024-02-08T18:48:40.464417 #60711] DEBUG -- :   Employee Load (0.1ms)  SELECT "employees".* FROM "employees" WHERE "employees"."transaction_from" <= ? AND "employees"."transaction_to" > ? AND "employees"."valid_from" <= ? AND "employees"."valid_to" > ? AND "employees"."bitemporal_id" = ? LIMIT ?  [["transaction_from", "2024-02-08 09:48:40.463656"], ["transaction_to", "2024-02-08 09:48:40.463656"], ["valid_from", "2024-02-08 09:48:40.463637"], ["valid_to", "2024-02-08 09:48:40.463637"], ["bitemporal_id", 1], ["LIMIT", 1]]
D, [2024-02-08T18:48:40.464720 #60711] DEBUG -- :   Employee Update (0.0ms)  UPDATE "employees" SET "transaction_to" = ? WHERE "employees"."id" = ?  [["transaction_to", "2024-02-08 09:48:40.463637"], ["id", 1]]
D, [2024-02-08T18:48:40.464936 #60711] DEBUG -- :   TRANSACTION (0.0ms)  SAVEPOINT active_record_1
D, [2024-02-08T18:48:40.464994 #60711] DEBUG -- :   Employee Create (0.1ms)  INSERT INTO "employees" ("bitemporal_id", "valid_from", "valid_to", "transaction_from", "transaction_to") VALUES (?, ?, ?, ?, ?) RETURNING "id"  [["bitemporal_id", 1], ["valid_from", "2024-02-08 09:48:40.462782"], ["valid_to", "2024-02-08 09:48:40.463637"], ["transaction_from", "2024-02-08 09:48:40.463637"], ["transaction_to", "9999-12-31 00:00:00"]]
D, [2024-02-08T18:48:40.465052 #60711] DEBUG -- :   TRANSACTION (0.0ms)  RELEASE SAVEPOINT active_record_1
D, [2024-02-08T18:48:40.465101 #60711] DEBUG -- :   TRANSACTION (0.0ms)  commit transaction
after_commit is invoked

wata727 avatar Feb 08 '24 09:02 wata727