Skip to content

Commit

Permalink
Allow Enumerable#pluck to take a splat.
Browse files Browse the repository at this point in the history
This allows easier integration with ActiveRecord, such that
AR#pluck will now use Enumerable#pluck if the relation is loaded,
without needing to hit the database.
  • Loading branch information
kddnewton committed May 29, 2015
1 parent 343dad9 commit 777fa25
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
4 changes: 4 additions & 0 deletions activerecord/lib/active_record/relation/calculations.rb
Expand Up @@ -161,6 +161,10 @@ def pluck(*column_names)
end
end

if loaded? && (column_names - @klass.column_names).empty?
return @records.pluck(*column_names)
end

if has_include?(column_names.first)
construct_relation_for_association_calculations.pluck(*column_names)
else
Expand Down
21 changes: 21 additions & 0 deletions activerecord/test/cases/calculations_test.rb
Expand Up @@ -632,6 +632,27 @@ def test_pluck_joined_with_polymorphic_relation
assert_equal [part.id], ShipPart.joins(:trinkets).pluck(:id)
end

def test_pluck_loaded_relation
companies = Company.order(:id).limit(3).load
assert_no_queries do
assert_equal ['37signals', 'Summit', 'Microsoft'], companies.pluck(:name)
end
end

def test_pluck_loaded_relation_multiple_columns
companies = Company.order(:id).limit(3).load
assert_no_queries do
assert_equal [[1, '37signals'], [2, 'Summit'], [3, 'Microsoft']], companies.pluck(:id, :name)
end
end

def test_pluck_loaded_relation_sql_fragment
companies = Company.order(:id).limit(3).load
assert_queries 1 do
assert_equal ['37signals', 'Summit', 'Microsoft'], companies.pluck('DISTINCT name')
end
end

def test_grouped_calculation_with_polymorphic_relation
part = ShipPart.create!(name: "has trinket")
part.trinkets.create!
Expand Down
11 changes: 9 additions & 2 deletions activesupport/lib/active_support/core_ext/enumerable.rb
Expand Up @@ -76,8 +76,15 @@ def without(*elements)
#
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
# => ["David", "Rafael", "Aaron"]
def pluck(key)
map { |element| element[key] }
#
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
# => [[1, "David"], [2, "Rafael"]]
def pluck(*keys)
if keys.many?
map { |element| keys.map { |key| element[key] } }
else
map { |element| element[keys.first] }
end
end
end

Expand Down
9 changes: 9 additions & 0 deletions activesupport/test/core_ext/enumerable_test.rb
Expand Up @@ -3,6 +3,8 @@
require 'active_support/core_ext/enumerable'

Payment = Struct.new(:price)
ExpandedPayment = Struct.new(:dollars, :cents)

class SummablePayment < Payment
def +(p) self.class.new(price + p.price) end
end
Expand Down Expand Up @@ -114,5 +116,12 @@ def test_without
def test_pluck
payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ])
assert_equal [5, 15, 10], payments.pluck(:price)

payments = GenericEnumerable.new([
ExpandedPayment.new(5, 99),
ExpandedPayment.new(15, 0),
ExpandedPayment.new(10, 50)
])
assert_equal [[5, 99], [15, 0], [10, 50]], payments.pluck(:dollars, :cents)
end
end

0 comments on commit 777fa25

Please sign in to comment.