Module: Activerecord::Transactionable::ClassMethods

Defined in:
lib/activerecord/transactionable.rb

Instance Method Summary collapse

Instance Method Details

#transaction_wrapper(object: nil, **args) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/activerecord/transactionable.rb', line 58

def transaction_wrapper(object: nil, **args)
  lock = args.delete(:lock)
  inside_args = extract_args(args, INSIDE_TRANSACTION_ERROR_HANDLERS)
  outside_args = extract_args(args, OUTSIDE_TRANSACTION_ERROR_HANDLERS)
  transaction_args = extract_args(args, TRANSACTION_METHOD_ARG_NAMES)
  transaction_open = ActiveRecord::Base.connection.transaction_open?
  unless args.keys.empty?
    raise ArgumentError,
      "#{self} does not know how to handle arguments: #{args.keys.inspect}"
  end
  if ERRORS_TO_DISALLOW_INSIDE_TRANSACTION.detect do |error|
    inside_args.values.flatten.uniq.include?(error)
  end
    raise ArgumentError,
      "#{self} should not rescue #{ERRORS_TO_DISALLOW_INSIDE_TRANSACTION.inspect} inside a transaction: #{inside_args.keys.inspect}"
  end

  if transaction_open
    if transaction_args[REQUIRES_NEW]
      logger.debug("[#{self}.transaction_wrapper] Will start a nested transaction.")
    else
      transaction_args[REQUIRES_NEW] = true
      logger.warn("[#{self}.transaction_wrapper] Opening a nested transaction. Setting #{REQUIRES_NEW}: true")
    end
  end
  error_handler_outside_transaction(
    object: object,
    transaction_open: transaction_open,
    **outside_args,
  ) do |outside_is_retry|
    run_inside_transaction_block(
      transaction_args: transaction_args,
      inside_args: inside_args,
      lock: lock,
      transaction_open: transaction_open,
      object: object,
    ) do |is_retry|
      # regardless of the retry being inside or outside the transaction, it is still a retry.
      yield outside_is_retry || is_retry
    end
  end
end