Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rails 6: after_commit on create callbacks are called after destroy on newly created records #511

Closed
nin9 opened this issue Jun 16, 2021 · 4 comments
Labels

Comments

@nin9
Copy link

nin9 commented Jun 16, 2021

When a record is created then destroyed, after_commit on create callbacks are called.

Steps to reproduce

Run the following ruby script:

require 'bundler/inline'
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', '6.0.0'
  # gem 'activerecord', '5.2.6' # this version works
  gem 'paranoia'
  gem 'sqlite3'
  gem 'byebug'
end

require 'active_record'
require 'minitest/autorun'
require 'paranoia'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.integer  :value, default: 0
    t.datetime :created_at
    t.datetime :updated_at
    t.datetime :deleted_at
  end
end

class User < ActiveRecord::Base
  acts_as_paranoid

  after_commit -> { self.value += 1 }, on: :create
end

class BugTest < Minitest::Test
  def test_freshly_loaded_model
    user = User.create!
    user.destroy

    # This should fail but it succeeds
    assert user.value == 2
  end
end

Note that if you called transaction_include_any_action?([:create]) inside the callback function it will return true which is wrong since the action is destroy not create.

@zhengpd
Copy link

zhengpd commented Aug 17, 2021

Got the same bug after upgraded to rails 6.1 & paranoia 2.4.3. I figured out a workaround by overwriting paranoia_destroy:

# config/initializers/fix_paranoia.rb
module Paranoia
  # override method in paranoia
  def paranoia_destroy
    transaction do
      run_callbacks(:destroy) do
        @_disable_counter_cache = deleted?
        result = paranoia_delete
        next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
        each_counter_cached_associations do |association|
          foreign_key = association.reflection.foreign_key.to_sym
          next if destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
          next unless send(association.reflection.name)
          association.decrement_counters
        end
        @_trigger_destroy_callback = true
        @_disable_counter_cache = false

        # Modified line
        # fix the after_commit callback bug
        # https://github.com/rubysherpas/paranoia/issues/511
        @_new_record_before_last_commit = false

        result
      end
    end
  end
  alias_method :destroy, :paranoia_destroy
end

@bkDJ
Copy link
Contributor

bkDJ commented Dec 3, 2021

@nin9 @zhengpd I also made a PR for this: #513

@mathieujobin
Copy link
Collaborator

fix will be released as v2.5.4 later

@mathieujobin
Copy link
Collaborator

released as v2.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants