Class: RuboCop::Cop::Rails::WhereRange

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

Overview

Identifies places where manually constructed SQL in ‘where` can be replaced with ranges.

Examples:

# bad
User.where('age >= ?', 18)
User.where.not('age >= ?', 18)
User.where('age < ?', 18)
User.where('age >= ? AND age < ?', 18, 21)
User.where('age >= :start', start: 18)
User.where('users.age >= ?', 18)

# good
User.where(age: 18..)
User.where.not(age: 18..)
User.where(age: ...18)
User.where(age: 18...21)
User.where(users: { age: 18.. })

# good
# There are no beginless ranges in ruby.
User.where('age > ?', 18)

Constant Summary collapse

MSG =
'Use `%<good_method>s` instead of manually constructing SQL.'
RESTRICT_ON_SEND =
%i[where not].freeze
GTEQ_ANONYMOUS_RE =

column >= ?

/\A\s*([\w.]+)\s+>=\s+\?\s*\z/.freeze
LTEQ_ANONYMOUS_RE =

column <[=] ?

/\A\s*([\w.]+)\s+(<=?)\s+\?\s*\z/.freeze
RANGE_ANONYMOUS_RE =

column >= ? AND column <[=] ?

/\A\s*([\w.]+)\s+>=\s+\?\s+AND\s+\1\s+(<=?)\s+\?\s*\z/i.freeze
GTEQ_NAMED_RE =

column >= :value

/\A\s*([\w.]+)\s+>=\s+:(\w+)\s*\z/.freeze
LTEQ_NAMED_RE =

column <[=] :value

/\A\s*([\w.]+)\s+(<=?)\s+:(\w+)\s*\z/.freeze
RANGE_NAMED_RE =

column >= :value1 AND column <[=] :value2

/\A\s*([\w.]+)\s+>=\s+:(\w+)\s+AND\s+\1\s+(<=?)\s+:(\w+)\s*\z/i.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

#on_send(node) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rubocop/cop/rails/where_range.rb', line 70

def on_send(node)
  return if node.method?(:not) && !where_not?(node)

  where_range_call?(node) do |template_node, values_node|
    column, value = extract_column_and_value(template_node, values_node)

    return unless column

    range = offense_range(node)
    good_method = build_good_method(node.method_name, column, value)
    message = format(MSG, good_method: good_method)

    add_offense(range, message: message) do |corrector|
      corrector.replace(range, good_method)
    end
  end
end