Skip to content

Commit 48710fa

Browse files
authored
Merge pull request #1549 from viralpraxis/fix-rails-inverse-of-cop-false-positives-when-using-dynamic-association-options
Fix `Rails/InverseOf` cop false positives when using dynamic assoc options
2 parents 84c131f + 5f8b62a commit 48710fa

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1549](https://github.com/rubocop/rubocop-rails/pull/1549): Fix `Rails/InverseOf` cop false positives when using dynamic association options. ([@viralpraxis][])

lib/rubocop/cop/rails/inverse_of.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class InverseOf < Base
178178
(pair (sym :inverse_of) nil)
179179
PATTERN
180180

181+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
181182
def on_send(node)
182183
recv, arguments = association_recv_arguments(node)
183184
return unless arguments
@@ -192,9 +193,11 @@ def on_send(node)
192193
return unless scope?(arguments) || options_requiring_inverse_of?(options)
193194

194195
return if options_contain_inverse_of?(options)
196+
return if dynamic_options?(options) && options.none? { |opt| inverse_of_nil_option?(opt) }
195197

196198
add_offense(node.loc.selector, message: message(options))
197199
end
200+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
198201

199202
def scope?(arguments)
200203
!ignore_scopes? && arguments.any?(&:block_type?)
@@ -216,6 +219,10 @@ def options_ignoring_inverse_of?(options)
216219
end
217220
end
218221

222+
def dynamic_options?(options)
223+
options.any? { |option| option&.kwsplat_type? }
224+
end
225+
219226
def options_contain_inverse_of?(options)
220227
options.any? { |opt| inverse_of_option?(opt) }
221228
end

spec/rubocop/cop/rails/inverse_of_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ class Person
2424
RUBY
2525
end
2626

27+
it 'registers an offense when specifying `inverse_of: nil` with dynamic options' do
28+
expect_offense(<<~RUBY)
29+
class Person
30+
def define_association(**options)
31+
has_many :foo, -> () { where(bar: true) }, inverse_of: nil, **options
32+
^^^^^^^^ You specified `inverse_of: nil`, you probably meant to use `inverse_of: false`.
33+
end
34+
end
35+
RUBY
36+
end
37+
2738
context 'when `IgnoreScopes: true`' do
2839
let(:cop_config) do
2940
{ 'IgnoreScopes' => true }
@@ -70,6 +81,16 @@ class Person
7081
end
7182
RUBY
7283
end
84+
85+
it 'does not register an offense with dynamic options' do
86+
expect_no_offenses(<<~RUBY)
87+
class Person
88+
def define_association(**options)
89+
has_many :foo, conditions: -> { where(bar: true) }, **options
90+
end
91+
end
92+
RUBY
93+
end
7394
end
7495

7596
context 'with scope and options' do
@@ -82,6 +103,16 @@ class Person
82103
RUBY
83104
end
84105

106+
it 'does not register an offense with dynamic options' do
107+
expect_no_offenses(<<~RUBY)
108+
class Person
109+
def define_association(**options)
110+
has_many(:foo, -> { group 'x' }, dependent: :destroy, **options)
111+
end
112+
end
113+
RUBY
114+
end
115+
85116
it 'does not register an offense when specifying `:inverse_of`' do
86117
expect_no_offenses("has_many :foo, -> { group 'x' }, dependent: :destroy, inverse_of: :baz")
87118
end

0 commit comments

Comments
 (0)