Class: RuboCop::Cop::Rails::WhereMissing

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector, TargetRailsVersion
Includes:
RangeHelp
Defined in:
lib/rubocop/cop/rails/where_missing.rb

Overview

Use ‘where.missing(…)` to find missing relationship records.

This cop is enabled in Rails 6.1 or higher.

Examples:

# bad
Post.left_joins(:author).where(authors: { id: nil })

# good
Post.where.missing(:author)

Constant Summary collapse

MSG =
'Use `where.missing(:%<left_joins_association>s)` instead of ' \
'`%<left_joins_method>s(:%<left_joins_association>s).where(%<where_association>s: { id: nil })`.'
RESTRICT_ON_SEND =
%i[left_joins left_outer_joins].freeze

Constants included from TargetRailsVersion

TargetRailsVersion::USES_REQUIRES_GEM_API

Instance Method Summary collapse

Methods included from TargetRailsVersion

minimum_target_rails_version, support_target_rails_version?

Instance Method Details

#missing_relationship(node) ⇒ Object



34
35
36
# File 'lib/rubocop/cop/rails/where_missing.rb', line 34

def_node_search :missing_relationship, <<~PATTERN
  (pair (sym _) (hash (pair (sym :id) (nil))))
PATTERN

#on_send(node) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rubocop/cop/rails/where_missing.rb', line 38

def on_send(node)
  return unless node.first_argument&.sym_type?

  root_receiver = root_receiver(node)
  where_node_and_argument(root_receiver) do |where_node, where_argument|
    next unless root_receiver == root_receiver(where_node)
    next unless same_relationship?(where_argument, node.first_argument)

    range = range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
    register_offense(node, where_node, where_argument, range)
    break
  end
end

#where_node_and_argument(node) ⇒ Object



29
30
31
# File 'lib/rubocop/cop/rails/where_missing.rb', line 29

def_node_search :where_node_and_argument, <<~PATTERN
  $(send ... :where (hash <(pair $(sym _) (hash (pair (sym :id) (nil))))...> ))
PATTERN