From a382d60f6abc94b6a965525872f858e48abc00de Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Wed, 30 Nov 2011 11:03:00 +0200 Subject: [PATCH] ActiveRecord::Relation#pluck method --- activerecord/CHANGELOG.md | 9 +++++++ .../associations/collection_proxy.rb | 2 +- activerecord/lib/active_record/base.rb | 2 +- .../active_record/relation/calculations.rb | 17 +++++++++++++ activerecord/test/cases/calculations_test.rb | 25 +++++++++++++++++++ .../source/active_record_querying.textile | 9 +++++++ 6 files changed, 62 insertions(+), 2 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 1a95b8e95e..f798b03ea1 100644 --- a/activerecord/CHANGELOG.md +++ b/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: diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 3181ca9a32..80bc4990d2 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -39,7 +39,7 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 484fe5fb16..2a02380591 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -449,7 +449,7 @@ module ActiveRecord #:nodoc: 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 diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index af86771d2d..0f57e9831d 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -166,6 +166,23 @@ module ActiveRecord 0 end + # This method is designed to perform select by a single column as direct SQL query + # Returns Array 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 = {}) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index c38814713a..5abf3d1af4 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/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 @@ class CalculationsTest < ActiveRecord::TestCase 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 diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index c4724f182e..073f7c143d 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -1146,6 +1146,15 @@ h3. +select_all+ Client.connection.select_all("SELECT * FROM clients WHERE id = '1'") +h3. +pluck+ + +pluck 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. + + +Client.where(:active => true).pluck(:id) # SELECT id FROM clients WHERE clients.active +Client.uniq.pluck(:role) # SELECT DISTINCT role FROM clients + + 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+.