Как получить значения одного столбца в массив

80

Прямо сейчас я делаю что-то вроде этого, чтобы выбрать один столбец данных:

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

Затем, передав их методу, я бы хотел, чтобы мой метод оставался агностическим, и теперь мне нужно вызывать hash.point из моего метода. Как я могу быстро преобразовать это в массив и передать набор данных моему методу, или есть способ лучше?

Франклин Стайн
источник

Ответы:

190

В Rails 3.2 есть метод потроха для этого

Именно так:

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)

Разница между uniq и отличным

одинокий
источник
Как массив может наследовать порядок результатов запроса с помощью pluck?
Франклин Стайн
3
Post.order (: score) .pluck (: score) - это решение. Благодарю.
Франклин Стайн
6
Для того, чтобы срывать иду есть специальный метод: Person.ids.
shock_one
Также загляните в драгоценный камень Эрни Миллера Valium github.com/ernie/valium, особенно если вы используете более старую
Джеймс Дэниэлс
Начиная с Rails 5.0, теперь рекомендуется использовать distinctвместо uniq: soPerson.distinct.pluck(:role)
Дэвид
15

Вы должны использовать pluckметод, предложенный @alony. Если вы застряли до Rails 3.2, вы можете использовать selectметод ActiveRecord вместе с Array#map:

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

до Ruby 1.9 вам пришлось бы это сделать .map{|x| x.title}, потому что Symbol#to_proc(псевдоним унарного &оператора) не определен в более ранних версиях Ruby.

Патрик Оссити
источник
Благодарю. Я видел, как вы комментировали новый метод Pluck. Можете ли вы сделать то же самое с этим?
Франклин Стайн
Да, если вы внимательно прочитаете ответ @alony, вы заметите, что она уже включила пример, который делает это.
Patrick Oscity
5

Если вы видите определение select_values, то оно использует 'map (&: field_name)'

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

Обычный и общий способ Rails собрать все значения полей в массиве выглядит так:

points = Post.all(:select => 'point').map(&:point)
Вик
источник
Хорошая точка зрения. Спасибо. Это отлично работает и позволяет мне по-прежнему применять порядок и другие вещи к запросу, в отличие от примера Post.select.
franklin stine
Я не согласен с вами, @franklinstine: Post.select(:point).limit(1)выполняет, SELECT point FROM "posts" LIMIT 1а Post.all(:select => :point).limit(1)повышает NoMethodError. Пожалуйста, поправьте меня, если я ошибаюсь.
Patrick Oscity
Я согласен с вашими комментариями. Но я не понимаю, где упомянуть в сообщении, чтобы использовать: Post.all (: select =>: point) .limit (1) Конечно, это выдаст ошибку «undefined method` limit '»
Вик,
@franklinstine сказал, что предпочитает ваш метод, потому что он мог бы связать другие утверждения после него, я просто хотел прояснить, что это неправда
Патрик Оссити
Да @padde вы ошиблись. Я говорил, что вы все еще можете применять порядок и другие операторы запроса, такие как: Post.all (: select => 'score',: order => 'score ASC'). Map (&: score).
Франклин Стайн
2
points = Post.all.collect {|p| p.point}
Rajibchowdhury
источник
2
Это работает, но вы выбираете все поля из базы данных, а затем фильтруете результат в Ruby, тогда как selectоператор выбирает только указанные столбцы.
Patrick Oscity