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