Skip to content

Commit e755c55

Browse files
committed
Fix a false positive for Rails/WhereMissing when left_joins(:foo) and where(foos: {id: nil}) separated by or, and
This PR is fix a false positive for `Rails/WhereMissing` when `left_joins(:foo)` and `where(foos: {id: nil})` separated by `or`, `and`. It is necessary to consider the following cases, which are separated by `or` or `and`. ```ruby Foo.left_joins(:foo).or(Foo.where(foos: {id: nil})) Foo.where(foos: {id: nil}).and(Foo.left_joins(:foo)) ```
1 parent 363ed1e commit e755c55

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#871](https://github.com/rubocop/rubocop-rails/pull/871): Fix a false positive for `Rails/WhereMissing` when `left_joins(:foo)` and `where(foos: {id: nil})` separated by `or`, `and`. ([@ydah][])

lib/rubocop/cop/rails/where_missing.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ class WhereMissing < Base
3838
def on_send(node)
3939
return unless node.first_argument.sym_type?
4040

41-
where_node_and_argument(root_receiver(node)) do |where_node, where_argument|
41+
root_receiver = root_receiver(node)
42+
where_node_and_argument(root_receiver) do |where_node, where_argument|
43+
next unless root_receiver == root_receiver(where_node)
4244
next unless same_relationship?(where_argument, node.first_argument)
4345

4446
range = range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
@@ -50,7 +52,12 @@ def on_send(node)
5052
private
5153

5254
def root_receiver(node)
53-
node&.parent&.send_type? ? root_receiver(node.parent) : node
55+
parent = node.parent
56+
if !parent&.send_type? || parent.method?(:or) || parent.method?(:and)
57+
node
58+
else
59+
root_receiver(parent)
60+
end
5461
end
5562

5663
def same_relationship?(where, left_joins)

spec/rubocop/cop/rails/where_missing_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,40 @@ def test
230230
RUBY
231231
end
232232

233+
it 'does not register an offense when `left_joins(:foo)` and `where(foos: {id: nil})` separated by `or`' do
234+
expect_no_offenses(<<~RUBY)
235+
Foo.left_joins(:foo).or(Foo.where(foos: {id: nil}))
236+
RUBY
237+
end
238+
239+
it 'does not register an offense when `left_joins(:foo)` and `where(foos: {id: nil})` separated by `and`' do
240+
expect_no_offenses(<<~RUBY)
241+
Foo.where(foos: {id: nil}).and(Foo.left_joins(:foo))
242+
RUBY
243+
end
244+
245+
it 'registers an offense when using `left_joins(:foo).where(foo: {id: nil})` outside `or` conditional expression' do
246+
expect_offense(<<~RUBY)
247+
Foo.left_joins(:foo).where(foos: {id: nil}).or(Foo.where(bar: "bar").left_joins(:foo))
248+
^^^^^^^^^^^^^^^^ Use `where.missing(:foo)` instead of `left_joins(:foo).where(foos: { id: nil })`.
249+
RUBY
250+
251+
expect_correction(<<~RUBY)
252+
Foo.where.missing(:foo).or(Foo.where(bar: "bar").left_joins(:foo))
253+
RUBY
254+
end
255+
256+
it 'registers an offense when using `left_joins(:foo).where(foo: {id: nil})` within `and` conditional expression' do
257+
expect_offense(<<~RUBY)
258+
Foo.left_joins(:foo).where(bar: "bar").and(Foo.where(foos: {id: nil}).left_joins(:foo))
259+
^^^^^^^^^^^^^^^^ Use `where.missing(:foo)` instead of `left_joins(:foo).where(foos: { id: nil })`.
260+
RUBY
261+
262+
expect_correction(<<~RUBY)
263+
Foo.left_joins(:foo).where(bar: "bar").and(Foo.where.missing(:foo))
264+
RUBY
265+
end
266+
233267
it "registers an offense when using `left_joins(:foo).where(foos: {id: nil}, bar: 'bar')` " \
234268
"with other `left_joins(:foo).where(foos: {id: nil}, bar: 'bar')`" do
235269
expect_offense(<<~RUBY)

0 commit comments

Comments
 (0)