class RuboCop::Cop::Rails::Pluck

{ a: :b, c: :d }].pluck(:a)
Post.published.pluck(:title)
# good
[{ a: :b, c: :d }].collect { |el| el[:a

}
Post.published.map { |post| post }
# bad
@example
—-
User.select(‘name AS nickname’).pluck(:nickname) # => raises ActiveRecord::StatementInvalid
# After autocorrection
User.select(‘name AS nickname’).map { |user| user } # => array of nicknames
# Original code
—-
[source,ruby]

This cop is unsafe because model can use column aliases.
@safety
—-
end
users.pluck(:id) # A query is executed on every iteration
5.times do
users = User.all
end
users.map { |user| user } # Only one query is executed
5.times do
users = User.all
—-
[source,ruby]

to prevent such potential issues.
This cop ignores offenses for ‘map/collect` when they are suspected to be part of an iteration
it may result in N+1 queries because `pluck` queries the database on each iteration.
NOTE: If the receiver’s relation is not loaded and ‘pluck` is used inside an iteration,
results in a more efficient query that only selects the necessary key.
element in an enumerable. When called on an Active Record relation, it
`pluck` can be used instead of `map` to extract a single key from each
Enforces the use of `pluck` over `map`.

def message(replacement, node)

def message(replacement, node)
  current = offense_range(node).source
  format(MSG, replacement: replacement, current: current)
end

def offense_range(node)

def offense_range(node)
  node.send_node.loc.selector.join(node.loc.end)
end

def on_block(node)

rubocop:disable Metrics/AbcSize
def on_block(node)
  return if node.each_ancestor(:any_block).any?
  pluck_candidate?(node) do |argument, key|
    next if key.regexp_type? || !use_one_block_argument?(argument)
    match = if node.block_type?
              block_argument = argument.children.first.source
              use_block_argument_in_key?(block_argument, key)
            elsif node.numblock_type?
              use_block_argument_in_key?('_1', key)
            else # itblock
              use_block_argument_in_key?('it', key)
            end
    next unless match
    register_offense(node, key)
  end
end

def register_offense(node, key)

def register_offense(node, key)
  replacement = "pluck(#{key.source})"
  message = message(replacement, node)
  add_offense(offense_range(node), message: message) do |corrector|
    corrector.replace(offense_range(node), replacement)
  end
end

def use_block_argument_in_key?(block_argument, key)

def use_block_argument_in_key?(block_argument, key)
  return false if block_argument == key.source
  key.each_descendant(:lvar).none? { |lvar| block_argument == lvar.source }
end

def use_one_block_argument?(argument)

def use_one_block_argument?(argument)
  # Checks for numbered argument `_1` or `it block parameter.
  return true if [1, :it].include?(argument)
  argument.respond_to?(:one?) && argument.one?
end