File: test_after_commit.rb

package info (click to toggle)
ruby-test-after-commit 0.2.3%2Bgh-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 120 kB
  • ctags: 30
  • sloc: ruby: 333; makefile: 2
file content (76 lines) | stat: -rw-r--r-- 2,690 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
require 'test_after_commit/version'

module TestAfterCommit
end

ActiveRecord::ConnectionAdapters::DatabaseStatements.class_eval do
  def transaction_with_transactional_fixtures(*args)
    @test_open_transactions ||= 0
    transaction_without_transactional_fixtures(*args) do
      begin
        @test_open_transactions += 1
        result = yield
      rescue ActiveRecord::Rollback, ActiveRecord::RecordInvalid => e
        rolled_back = true
        raise e
      ensure
        if @test_open_transactions == 1 && !rolled_back
          test_commit_records
        end
        @test_open_transactions -= 1
        result
      end
    end
  end
  alias_method_chain :transaction, :transactional_fixtures

  def test_commit_records
    if ActiveRecord::VERSION::MAJOR == 3
      commit_transaction_records(false)
    else
      @transaction.commit_records
      @transaction.records.clear # prevent duplicate .commit!
      @transaction.instance_variable_get(:@state).set_state(nil)
    end
  end

  if ActiveRecord::VERSION::MAJOR == 3
    # The @_current_transaction_records is a stack of arrays, each one
    # containing the records associated with the corresponding transaction
    # in the transaction stack. This is used by the
    # `rollback_transaction_records` method (to only send a rollback hook to
    # models attached to the transaction being rolled back) but is usually
    # ignored by the `commit_transaction_records` method. Here we
    # monkey-patch it to temporarily replace the array with only the records
    # for the top-of-stack transaction, so the real
    # `commit_transaction_records` method only sends callbacks to those.
    #
    def commit_transaction_records_with_transactional_fixtures(commit = true)
      return commit_transaction_records_without_transactional_fixtures if commit

      preserving_current_transaction_records do
        @_current_transaction_records = @_current_transaction_records.pop || []
        commit_transaction_records_without_transactional_fixtures
      end
    end
    alias_method_chain :commit_transaction_records, :transactional_fixtures

    def preserving_current_transaction_records
      old_current_transaction_records = @_current_transaction_records.dup
      yield
    ensure
      @_current_transaction_records = old_current_transaction_records
    end
  end
end

if ActiveRecord::VERSION::MAJOR >= 4
  # disable parts of the sync code that starts looping
  ActiveRecord::Base.class_eval do
    alias_method :sync_with_transaction_state_with_state, :sync_with_transaction_state
    def sync_with_transaction_state
      @reflects_state[0] = true
      sync_with_transaction_state_with_state
    end
  end
end