class RuboCop::Cop::Rails::UniqBeforePluck
Prefer the use of distinct, before pluck instead of after.
The use of distinct before pluck is preferred because it executes within the database.
This cop has two different enforcement modes. When the EnforcedStyle is conservative (the default) then only calls to pluck on a constant (i.e. a model class) before distinct are added as offenses.
When the EnforcedStyle is aggressive then all calls to pluck before distinct are added as offenses. This may lead to false positives as the cop cannot distinguish between calls to pluck on an ActiveRecord::Relation vs a call to pluck on an ActiveRecord::Associations::CollectionProxy.
This cop is unsafe because the behavior may change depending on the database collation. Autocorrect is disabled by default for this cop since it may generate false positives.
@example EnforcedStyle: conservative (default)
# bad Model.pluck(:id).uniq # good Model.distinct.pluck(:id)
@example EnforcedStyle: aggressive
# bad # this will return a Relation that pluck is called on Model.where(cond: true).pluck(:id).uniq # bad # an association on an instance will return a CollectionProxy instance.assoc.pluck(:id).uniq # bad Model.pluck(:id).uniq # good Model.distinct.pluck(:id)
Constants
- MSG
- NEWLINE
- PATTERN
- RESTRICT_ON_SEND
Public Instance Methods
# File lib/rubocop/cop/rails/uniq_before_pluck.rb, line 65 def on_send(node) method = if style == :conservative conservative_node_match(node) else aggressive_node_match(node) end return unless method add_offense(node.loc.selector) do |corrector| method = node.method_name corrector.remove(dot_method_with_whitespace(method, node)) corrector.insert_before(node.receiver.loc.dot.begin, '.distinct') end end
Private Instance Methods
# File lib/rubocop/cop/rails/uniq_before_pluck.rb, line 93 def dot_method_begin_pos(method, node) lines = node.source.split(NEWLINE) if lines.last.strip == ".#{method}" node.source.rindex(NEWLINE) else node.loc.dot.begin_pos end end
# File lib/rubocop/cop/rails/uniq_before_pluck.rb, line 88 def dot_method_with_whitespace(method, node) range_between(dot_method_begin_pos(method, node), node.loc.selector.end_pos) end
# File lib/rubocop/cop/rails/uniq_before_pluck.rb, line 84 def style_parameter_name 'EnforcedStyle' end