class RuboCop::Cop::Rails::WhereEquals
User.where(users: { name: ‘Gabe’ })
User.where(name: [‘john’, ‘jane’])
User.where(name: nil)
User.where(name: ‘Gabe’)
# good
User.where(‘users.name = :name’, name: ‘Gabe’)
User.where(‘name IN (:names)’, names: [‘john’, ‘jane’])
User.where(‘name IN (?)’, [‘john’, ‘jane’])
User.where(‘name IS NULL’)
User.where(‘name = :name’, name: ‘Gabe’)
User.where(‘name = ?’, ‘Gabe’)
# bad
@example
in ‘where` can be replaced with `where(attribute: value)`.
This cop identifies places where manually constructed SQL
def build_good_method(column, value)
def build_good_method(column, value) if column.include?('.') table, column = column.split('.') "where(#{table}: { #{column}: #{value} })" else "where(#{column}: #{value})" end end
def extract_column_and_value(template_node, value_node)
def extract_column_and_value(template_node, value_node) value = case template_node.value when EQ_ANONYMOUS_RE, IN_ANONYMOUS_RE value_node.source when EQ_NAMED_RE, IN_NAMED_RE return unless value_node&.hash_type? pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym } pair.value.source when IS_NULL_RE 'nil' else return end [Regexp.last_match(1), value] end
def offense_range(node)
def offense_range(node) range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos) end
def on_send(node)
def on_send(node) where_method_call?(node) do |template_node, value_node| value_node = value_node.first range = offense_range(node) column_and_value = extract_column_and_value(template_node, value_node) return unless column_and_value good_method = build_good_method(*column_and_value) message = format(MSG, good_method: good_method) add_offense(range, message: message) do |corrector| corrector.replace(range, good_method) end end end