85

Right now I'm doing something like this to select a single column of data:

points = Post.find_by_sql("select point from posts")

Then passing them to a method, I'd like my method to remain agnostic, and now have to call hash.point from within my method. How can I quickly convert this into an array and pass the data set to my method, or is there a better way?

0

4 Answers 4

199

In Rails 3.2 there is a pluck method for this

Just like this:

Person.pluck(:id) # SELECT people.id FROM people
Person.pluck(:role).uniq # unique roles from array of people
Person.distinct.pluck(:role) # SELECT DISTINCT role FROM people SQL
Person.where(:confirmed => true).limit(5).pluck(:id)

Difference between uniq and distinct

Sign up to request clarification or add additional context in comments.

5 Comments

How can an array inherit a query result's ordering with pluck?
Post.order(:score).pluck(:score) is the solution. Thanks.
To pluck ids there is a special method: Person.ids.
Also look into Ernie Miller's gem Valium github.com/ernie/valium especially if you're on an older Rails or want multiple columns
As of Rails 5.0, it is now recommended to use distinct instead of uniq: so Person.distinct.pluck(:role)
17

You should use the pluck method as @alony suggested. If you are stuck before Rails 3.2 you can use the ActiveRecord select method together with Array#map:

Post.select(:point).map(&:point)
#=> ["foo", "bar", "baz"] 

before Ruby 1.9 you'd have to do .map{|x| x.title} though, because Symbol#to_proc (aliased by the unary & operator) is not defined in earlier versions of Ruby.

2 Comments

Thanks. I saw you commented on the new Pluck method. Can you do the same with that?
Yes, if you read @alony's answer carefully, you will notice that she already included an example that does this.
5

If you see the definition of select_values , then it using 'map(&:field_name)'

  def select_values(arel, name = nil)
    result = select_rows(to_sql(arel), name)
    result.map { |v| v[0] }
  end

The common and general Rails way to collect all the fields values in array is like :

points = Post.all(:select => 'point').map(&:point)

6 Comments

Good point. Thank you. This works great, and lets me still apply order and other things to the query, unlike the Post.select example.
I dont agree with you, @franklinstine: Post.select(:point).limit(1) performs SELECT point FROM "posts" LIMIT 1 whereas Post.all(:select => :point).limit(1) raises a NoMethodError. Please correct me if i'm wrong.
I agree with your comments. But I am not getting where mention in the post to use : Post.all(:select => :point).limit(1) Ofcourse it will give error "undefined method `limit'"
@franklinstine said he prefers your method because he could chain other statements after it, i just wanted to make clear that this is not true
Yes @padde you mis-inferred. I was saying you can still apply order and other query statements such as: Post.all(:select => 'score', :order => 'score ASC').map(&:score).
|
3
points = Post.all.collect {|p| p.point}

1 Comment

This works, but you select all fields from the database and then filter the result in Ruby whereas the select statement only fetches the specified columns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.