diff --git a/changelog/change_inspect_with_lock_for_rails_transaction_exit_statement_cop.md b/changelog/change_inspect_with_lock_for_rails_transaction_exit_statement_cop.md new file mode 100644 index 0000000000..c81a74e89f --- /dev/null +++ b/changelog/change_inspect_with_lock_for_rails_transaction_exit_statement_cop.md @@ -0,0 +1 @@ +* [#710](https://github.com/rubocop/rubocop-rails/pull/710): Rails/TransactionExitStatement - Inspect `ActiveRecord::Locking::Pessimistic#with_lock` too, as `#with_lock` opens a transaction. ([@FunnyHector][https://github.com/FunnyHector]) diff --git a/lib/rubocop/cop/rails/transaction_exit_statement.rb b/lib/rubocop/cop/rails/transaction_exit_statement.rb index a73f5b3e5f..9150b362ea 100644 --- a/lib/rubocop/cop/rails/transaction_exit_statement.rb +++ b/lib/rubocop/cop/rails/transaction_exit_statement.rb @@ -29,6 +29,11 @@ module Rails # 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 @@ -47,7 +52,7 @@ class TransactionExitStatement < Base Exit 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} ...) diff --git a/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb b/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb index 49bd5e74cd..b8e2b0f5f5 100644 --- a/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb +++ b/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb @@ -28,6 +28,15 @@ RUBY end + it 'registers an offense when `return` is used in `with_lock` transactions' do + expect_offense(<<~RUBY) + user.with_lock do + return if user.active? + ^^^^^^ Exit statement `return` is not allowed. Use `raise` (rollback) or `next` (commit). + end + RUBY + end + it 'does not register an offense when `next` is used in transactions' do expect_no_offenses(<<~RUBY) ApplicationRecord.transaction do