Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ActiveRecord::Relation#pluck method

  • Loading branch information...
commit a382d60f6abc94b6a965525872f858e48abc00de 1 parent d9c2882
@bogdan bogdan authored
View
9 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:
View
2  activerecord/lib/active_record/associations/collection_proxy.rb
@@ -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
View
2  activerecord/lib/active_record/base.rb
@@ -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
View
17 activerecord/lib/active_record/relation/calculations.rb
@@ -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 = {})
View
25 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'
@@ -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
View
9 railties/guides/source/active_record_querying.textile
@@ -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+.

46 comments on commit a382d60

@jtmkrueger

+1 This looks super useful!

@ahawkins

+1 agree

@kennon

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

@brycethornton

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

@pcreux

+1 !

@Gimi

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

@crjones

+1 Very useful!

@cvshepherd

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

pluck yeah ;)

@pjg

+1 really useful piece of code

@anlek

+1 ;)

@guimello

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

@evilmarty

+2 because it's that good

@pi3r

Thanks a lot!

@dmitriy-kiriyenko

Does it work with serialization like ernie/valium?

@cvshepherd

@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.

@Gimi

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

@defsdoor

is "pluck" really the right name for this ?

@kurko

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

@whitethunder

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

@defsdoor

'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

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

@dmitriy-kiriyenko

values_at? =)

@dmitriy-kiriyenko

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

@kurko

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

@ckknight

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

@mariovisic

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

@sinisterchipmunk

+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

:+1: , I actually think values_at is better than pluck or project

@allochi

+1 multiple columns

@mcmorgan

+1 multiple columns

@jeremy
Owner

bike shed

@whitethunder

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

But seriously, project is a better name ;)

@dmitriy-kiriyenko

@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". =)

@ernie

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

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
Owner

@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

@jeremy pushing it up now -- thanks!

@ernie

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

@tenderlove
Owner

unicorn

@ernie

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

@cbetta

Love it! +1

@fmquaglia

wow, amazing +1

Please sign in to comment.
Something went wrong with that request. Please try again.