Skip to content

Commit e861a14

Browse files
committed
Add new Rails/PrivateTransactionOption cop
This PR adds a new cop called `Rails/PrivateTransactionOption`. This cop checks whether `ActiveRecord::Base.transaction(joinable: _)` is used. The `joinable` option is a private API and is not intended to be called from outside Active Record core. rails/rails#39912 (comment) rails/rails#46182 (comment) Passing `joinable: false` may cause unexpected behavior such as the `after_commit` callback not firing at the appropriate time.
1 parent 8293b58 commit e861a14

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1236](https://github.com/rubocop/rubocop-rails/pull/1236): Add new `Rails/PrivateTransactionOption`. ([@wata727][])

config/default.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,12 @@ Rails/Present:
782782
# Convert usages of `unless blank?` to `if present?`
783783
UnlessBlank: true
784784

785+
Rails/PrivateTransactionOption:
786+
Description: 'Avoid use of `ActiveRecord::Base.transaction(joinable: _)`.'
787+
Enabled: pending
788+
Safe: false
789+
VersionAdded: '<<next>>'
790+
785791
Rails/RakeEnvironment:
786792
Description: 'Include `:environment` as a dependency for all Rake tasks.'
787793
Enabled: true
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Rails
6+
# Checks whether `ActiveRecord::Base.transaction(joinable: _)` is used.
7+
#
8+
# The `joinable` option is a private API and is not intended to be called
9+
# from outside Active Record core.
10+
# https://github.com/rails/rails/issues/39912#issuecomment-665483779
11+
# https://github.com/rails/rails/issues/46182#issuecomment-1265966330
12+
#
13+
# Passing `joinable: false` may cause unexpected behavior such as the
14+
# `after_commit` callback not firing at the appropriate time.
15+
#
16+
# @safety
17+
# This Cop is unsafe because it cannot accurately identify
18+
# the `ActiveRecord::Base.transaction` method call.
19+
#
20+
# @example
21+
# # bad
22+
# ActiveRecord::Base.transaction(requires_new: true, joinable: false)
23+
#
24+
# # good
25+
# ActiveRecord::Base.transaction(requires_new: true)
26+
#
27+
class PrivateTransactionOption < Base
28+
MSG = 'Do not use `ActiveRecord::Base.transaction(joinable: _)`.'
29+
RESTRICT_ON_SEND = %i[transaction].freeze
30+
31+
# @!method match_transaction_with_joinable(node)
32+
def_node_matcher :match_transaction_with_joinable, <<~PATTERN
33+
(send _ :transaction (hash <$(pair (sym :joinable) {true false}) ...>))
34+
PATTERN
35+
36+
def on_send(node)
37+
match_transaction_with_joinable(node) do |option_node|
38+
add_offense(option_node)
39+
end
40+
end
41+
end
42+
end
43+
end
44+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
require_relative 'rails/pluralization_grammar'
8989
require_relative 'rails/presence'
9090
require_relative 'rails/present'
91+
require_relative 'rails/private_transaction_option'
9192
require_relative 'rails/rake_environment'
9293
require_relative 'rails/read_write_attribute'
9394
require_relative 'rails/redundant_active_record_all_method'
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::PrivateTransactionOption, :config do
4+
it 'registers an offense when using `joinable: false`' do
5+
expect_offense(<<~RUBY)
6+
ActiveRecord::Base.transaction(requires_new: true, joinable: false)
7+
^^^^^^^^^^^^^^^ Do not use `ActiveRecord::Base.transaction(joinable: _)`.
8+
RUBY
9+
end
10+
11+
it 'does not register an offense when using only `requires_new: true`' do
12+
expect_no_offenses(<<~RUBY)
13+
ActiveRecord::Base.transaction(requires_new: true)
14+
RUBY
15+
end
16+
end

0 commit comments

Comments
 (0)