lib/rubocop/cop/rails/transaction_exit_statement.rb in rubocop-rails-2.14.2 vs lib/rubocop/cop/rails/transaction_exit_statement.rb in rubocop-rails-2.15.0
- old
+ new
@@ -1,11 +1,11 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Rails
- # This cop checks for the use of exit statements (namely `return`,
+ # 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).
#
@@ -27,10 +27,15 @@
# # 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
@@ -45,22 +50,30 @@
class TransactionExitStatement < Base
MSG = <<~MSG.chomp
Exit statement `%<statement>s` is not allowed. Use `raise` (rollback) or `next` (commit).
MSG
- RESTRICT_ON_SEND = %i[transaction].freeze
+ RESTRICT_ON_SEND = %i[transaction with_lock].freeze
def_node_search :exit_statements, <<~PATTERN
({return | break | send nil? :throw} ...)
PATTERN
+ def_node_matcher :rescue_body_return_node?, <<~PATTERN
+ (:resbody ...
+ ...
+ ({return | break | send nil? :throw} ...)
+ ...
+ )
+ PATTERN
+
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 in_rescue?(statement_node) || nested_block?(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)
@@ -77,16 +90,10 @@
else
statement_node.method_name
end
end
- def in_rescue?(statement_node)
- statement_node.ancestors.find(&:rescue_type?)
- end
-
def nested_block?(statement_node)
- return false unless statement_node.break_type?
-
!statement_node.ancestors.find(&:block_type?).method?(:transaction)
end
end
end
end