Class: RuboCop::Cop::Rails::TransactionExitStatement

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/rails/transaction_exit_statement.rb

Overview

Checks for the use of exit statements (namely `return`, `break` and `throw`) in transactions. This is due to the eventual unexpected behavior when using ActiveRecord >= 7, where transactions exitted using these statements are being rollbacked rather than committed (pre ActiveRecord 7 behavior).

As alternatives, it would be more intuitive to explicitly raise an error when rollback is desired, and to use `next` when commit is desired.

Examples:

# bad
ApplicationRecord.transaction do
  return if user.active?
end

# bad
ApplicationRecord.transaction do
  break if user.active?
end

# bad
ApplicationRecord.transaction do
  throw if user.active?
end

# bad, as `with_lock` implicitly opens a transaction too
user.with_lock do
  throw if user.active?
end

# good
ApplicationRecord.transaction do
  # Rollback
  raise "User is active" if user.active?
end

# good
ApplicationRecord.transaction do
  # Commit
  next if user.active?
end

See Also:

Constant Summary collapse

MSG =
<<~MSG.chomp
  Exit statement `%<statement>s` is not allowed. Use `raise` (rollback) or `next` (commit).
MSG
RESTRICT_ON_SEND =
%i[transaction with_lock].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rubocop/cop/rails/transaction_exit_statement.rb', line 69

def on_send(node)
  return unless (parent = node.parent)
  return unless parent.block_type? && parent.body

  exit_statements(parent.body).each do |statement_node|
    next if statement_node.break_type? && nested_block?(statement_node)

    statement = statement(statement_node)
    message = format(MSG, statement: statement)

    add_offense(statement_node, message: message)
  end
end