Skip to content

Commit

Permalink
ActiveRecord::Relation#pluck method
Browse files Browse the repository at this point in the history
  • Loading branch information
bogdan committed Nov 30, 2011
1 parent d9c2882 commit a382d60
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 2 deletions.
9 changes: 9 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,5 +1,14 @@
## Rails 3.2.0 (unreleased) ##


* Implemented ActiveRecord::Relation#pluck method

Method returns Array of column value from table under ActiveRecord model

Client.pluck(:id)

*Bogdan Gusiev*

* Automatic closure of connections in threads is deprecated. For example
the following code is deprecated:

Expand Down
Expand Up @@ -39,7 +39,7 @@ class CollectionProxy # :nodoc:
instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }

delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from,
:lock, :readonly, :having, :to => :scoped
:lock, :readonly, :having, :pluck, :to => :scoped

delegate :target, :load_target, :loaded?, :scoped,
:to => :@association
Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/base.rb
Expand Up @@ -449,7 +449,7 @@ class << self # Class methods
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
:having, :create_with, :uniq, :to => :scoped
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :to => :scoped

def inherited(child_class) #:nodoc:
# force attribute methods to be higher in inheritance hierarchy than other generated methods
Expand Down
17 changes: 17 additions & 0 deletions activerecord/lib/active_record/relation/calculations.rb
Expand Up @@ -166,6 +166,23 @@ def calculate(operation, column_name, options = {})
0
end

# This method is designed to perform select by a single column as direct SQL query
# Returns <tt>Array</tt> with values of the specified column name
# The values has same data type as column.
#
# Examples:
#
# Person.pluck(:id) # SELECT people.id FROM people
# Person.uniq.pluck(:role) # SELECT DISTINCT role FROM people
# Person.where(:confirmed => true).limit(5).pluck(:id)
#
def pluck(column_name)
scope = self.select(column_name)
self.connection.select_values(scope.to_sql).map! do |value|
type_cast_using_column(value, column_for(column_name))
end
end

private

def perform_calculation(operation, column_name, options = {})
Expand Down
25 changes: 25 additions & 0 deletions activerecord/test/cases/calculations_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/company'
require "models/contract"
require 'models/topic'
require 'models/edge'
require 'models/club'
Expand Down Expand Up @@ -446,4 +447,28 @@ def test_distinct_is_honored_when_used_with_count_operation_after_group
distinct_authors_for_approved_count = Topic.group(:approved).count(:author_name, :distinct => true)[true]
assert_equal distinct_authors_for_approved_count, 2
end

def test_pluck
assert_equal [1,2,3,4], Topic.order(:id).pluck(:id)
end

def test_pluck_type_cast
topic = topics(:first)
relation = Topic.where(:id => topic.id)
assert_equal [ topic.approved ], relation.pluck(:approved)
assert_equal [ topic.last_read ], relation.pluck(:last_read)
assert_equal [ topic.written_on ], relation.pluck(:written_on)

end

def test_pluck_and_uniq
assert_equal [50, 53, 55, 60], Account.order(:credit_limit).uniq.pluck(:credit_limit)
end

def test_pluck_in_relation
company = Company.first
contract = company.contracts.create!
assert_equal [contract.id], company.contracts.pluck(:id)
end

end
9 changes: 9 additions & 0 deletions railties/guides/source/active_record_querying.textile
Expand Up @@ -1146,6 +1146,15 @@ h3. +select_all+
Client.connection.select_all("SELECT * FROM clients WHERE id = '1'")
</ruby>

h3. +pluck+

<tt>pluck</tt> can be used to query single column from table under model. It accepts column name as argument and returns Array of values of the specified column with corresponding data type.

<ruby>
Client.where(:active => true).pluck(:id) # SELECT id FROM clients WHERE clients.active
Client.uniq.pluck(:role) # SELECT DISTINCT role FROM clients
</ruby>

h3. Existence of Objects

If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+.
Expand Down

46 comments on commit a382d60

@jtmkrueger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 This looks super useful!

@ahawkins
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 agree

@kennon
Copy link

@kennon kennon commented on a382d60 Nov 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As someone who has literally had to write "Order.select("id").collect(&:id)" four times today, this is a big +1 from me!

@brycethornton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've wanted a method like this for so long! I'm always writing little bits of code to do this. Thanks!

@pcreux
Copy link
Contributor

@pcreux pcreux commented on a382d60 Nov 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 !

@zliang-min
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @kennon, no SomeThing.select('col').map(&:col) any more!

@crjones
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 Very useful!

@cvshepherd
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't try this out at the the moment, so here's a question: How would this compare to https://github.com/ernie/valium ? Same thing / functionality?

@subdigital
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pluck yeah ;)

@pjg
Copy link
Contributor

@pjg pjg commented on a382d60 Nov 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 really useful piece of code

@anlek
Copy link

@anlek anlek commented on a382d60 Nov 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 ;)

@guimello
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not several columns? Wouldn't it be as useful? or am I missing something here?

@evilmarty
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+2 because it's that good

@pi3r
Copy link

@pi3r pi3r commented on a382d60 Dec 1, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot!

@dmitriy-kiriyenko
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work with serialization like ernie/valium?

@cvshepherd
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmitriy-kiriyenko Since no one answered my previous question about how it compares to valium, and judging by the other comments, I'd say no one here actually knew about valium.

@zliang-min
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvshepherd just got to know valium, and I think it's better.

@defsdoor
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is "pluck" really the right name for this ?

@kurko
Copy link

@kurko kurko commented on a382d60 Dec 1, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1: Is "pluck" really the right name for this ?

@whitethunder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seriously, I would propose 'project' as a better name

@defsdoor
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'project' is just as un-obvious. For a method that returns an array of columns I'd expect the method name to have something to do with getting an array of columns....

Something like 'selective_columns' and extend it to return optionally more than one column.

@whitethunder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not un-obvious if you've heard of an SQL projection

@dmitriy-kiriyenko
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

values_at? =)

@dmitriy-kiriyenko
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I definitely like project. +1 for project.
We'll have another reserved word to avoid in business code.

@jweslley
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@kurko
Copy link

@kurko kurko commented on a382d60 Dec 1, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, but I doubt it'll be changed anyway.

@ckknight
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being able to "pluck" multiple columns would be quite useful as well.

@mariovisic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 although I think values_at (what valium uses) would be a better name than pluck.

@sinisterchipmunk
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, but I actually like "pluck". It's used pretty rarely in everyday speech, and to me seeing it is odd enough that I'll remember it as a method name. -- like "tap", the other most awesome method name ever! Plus, "pluck" is such a fun word!

@leomao10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 , I actually think values_at is better than pluck or project

@allochi
Copy link

@allochi allochi commented on a382d60 Dec 4, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 multiple columns

@marcelmorgan
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 multiple columns

@jeremy
Copy link
Member

@jeremy jeremy commented on a382d60 Dec 4, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bike shed

@whitethunder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Green??? What a stupid color for a bikeshed.

But seriously, project is a better name ;)

@dmitriy-kiriyenko
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@whitethunder, I told them, but they don't trust me. Seriously, project is an excellent name. More, I'm looking forward for a method like "user" or "company". Also a great idea would be methods "topic", "post" and "comment". =)

@sj26
Copy link
Contributor

@sj26 sj26 commented on a382d60 Dec 5, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ernie
Copy link
Contributor

@ernie ernie commented on a382d60 Dec 5, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For those who were asking, it looks like this patch handles serialized columns, because Column#type_cast decodes encoded columns in current master.

This wasn't the case in 3-0-stable, which is why Valium's implementation is (only slightly) more involved.

I agree with @jeremy, though -- this is a whole lot of discussion for a very simple change. In fact, I'd have submitted Valium's implementation as a patch long ago if I'd thought it had a chance to be accepted. One of those things where it was so ridiculously simple that I figured there was a reason it wasn't part of the AR API already. ;)

@ernie
Copy link
Contributor

@ernie ernie commented on a382d60 Dec 5, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I take back my comment about working with serialization. It looks like the only place that a Column's coder is being set in the current AR code is in 3 tests in column_definition_test at this point, unless I missed something. It doesn't look like SchemaCache would be the right place to handle this, either.

Anyway, I have a rough version of Valium's take on this ported to a Rails 3.2 patch and passing all but the serialization tests (due to the issue mentioned). I can work out the remaining issues there and submit a value(s)_of implementation for Rails 3.2 if the core team is interested.

@jeremy
Copy link
Member

@jeremy jeremy commented on a382d60 Dec 6, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ernie Cool, yeah, let's see it. Wish we'd known you had Valium already implemented, sorry about that. Pull request came in; didn't look for prior art. Thanks for pitching in in any case.

@ernie
Copy link
Contributor

@ernie ernie commented on a382d60 Dec 6, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeremy pushing it up now -- thanks!

@Mab879
Copy link

@Mab879 Mab879 commented on a382d60 Dec 6, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ernie
Copy link
Contributor

@ernie ernie commented on a382d60 Dec 6, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For those visiting this thread: See #3871 for the pull request with alternate implementation supporting serialization, multiple values, etc.

@tenderlove
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unicorn

@ernie
Copy link
Contributor

@ernie ernie commented on a382d60 Dec 6, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tenderlove unicorns, rainbows and ponies would be the "etc" part

@cbetta
Copy link

@cbetta cbetta commented on a382d60 Dec 7, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it! +1

@fmquaglia
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, amazing +1

Please sign in to comment.