Rails - учитывая массив Users - как получить вывод только электронных писем? - PullRequest
3 голосов
/ 01 марта 2011

У меня есть следующее:

@users = User.all

У пользователя есть несколько полей, включая электронную почту.

Я бы хотел получить список всех писем @users.

Я пытался:

@users.email.all but that errors w undefined

Идеи? Спасибо

Ответы [ 7 ]

12 голосов
/ 02 марта 2011

(по многочисленным просьбам, размещение в качестве реального ответа)

Что мне не нравится в решении fl00r , так это то, что оно создает новый объект User для каждой записи в БД; который просто не масштабируется. Это здорово для таблицы, в которой всего 10 писем, но как только вы начнете получать тысячи, вы столкнетесь с проблемами, в основном с потреблением памяти Ruby.

Эту небольшую проблему можно обойти, используя connection.select_values ​​на модели и немного совершенства ARel:

User.connection.select_values(User.select("email").to_sql)

Это даст вам прямые строки адресов электронной почты из базы данных. Нет проблем с пользовательскими объектами, и он будет масштабироваться лучше, чем прямой User.select("email") запрос, но я бы не сказал, что это «лучший масштаб». Возможно, есть лучшие способы сделать это, о которых я пока не знаю.

Дело в том, что объект String будет использовать путь * на 1015 * меньше памяти, чем объект User, поэтому вы можете иметь их больше. Это также более быстрый запрос и не имеет большого значения (выполнение запроса, затем сопоставление значений). О, и map тоже займет больше времени.

Если вы используете Rails 2.3 ...

Тогда вам придется сконструировать SQL вручную, извините, чтобы сказать.

User.connection.select_values("SELECT email FROM users")

Просто приведу еще один пример помощников, которые предоставляет Rails 3.

6 голосов
/ 02 марта 2011
User.select(:email).map(&:email)
5 голосов
/ 16 октября 2012

Я по-прежнему считаю, что connection.select_values ​​является правильным способом решения этой проблемы, но недавно я нашел метод AR по умолчанию, встроенный в Rails, который сделает это за вас: pluck.

В вашем примере все, что вам нужно сделать, это запустить:

User.pluck(:email)

Подход select_values ​​может быть быстрее на очень больших наборах данных, но это потому, что он не приводит к типу возвращаемых значений,Например, логические значения будут возвращены как они хранятся в базе данных (как 1 и 0), а не как true |false.

Метод pluck работает с ARel, поэтому вы можете создавать цепочки:

User.order('created_at desc').limit(5).pluck(:email)
2 голосов
/ 28 сентября 2012

Хотя я часто бываю в SO, я зарегистрировался только сегодня.К сожалению, это означает, что мне не хватает репутации, чтобы оставлять комментарии к ответам других людей.

Воспользовавшись ответом Райана выше, вы можете расширить ActiveRecord :: Base, чтобы создать метод, который позволит вам использоватьэто во всем вашем коде более понятным способом.

Создайте файл в config / initializer (например, config / initializers / active_record.rb):

class ActiveRecord::Base
  def self.selected_to_array
    connection.select_values(self.scoped)
  end
end

Затем вы можете связать этот метод по адресуконец ваших объявлений ARel:

User.select('email').selected_to_array
User.select('email').where('id > ?', 5).limit(4).selected_to_array
2 голосов
/ 01 марта 2011

Просто используйте:

User.select("email")
1 голос
/ 02 марта 2011

Используйте это, чтобы получить массив всех электронных писем:

@users.collect { |user| user.email }
# => ["test@example.com", "test2@example.com", ...]

Или сокращенную версию:

@users.collect(&:email)
0 голосов
/ 31 августа 2011

Вам следует избегать использования User.all.map(&:email), так как это создаст много объектов ActiveRecord, которые занимают большие объемы памяти, значительная часть которых не будет собираться сборщиком мусора Ruby.Это также сильно загружает процессор.

Если вы просто хотите собрать только несколько атрибутов из вашей базы данных, не жертвуя при этом производительностью, большим использованием памяти и циклами процессора, рассмотрите возможность использования Valium.

https://github.com/ernie/valium

Вот пример получения всех электронных писем от всех пользователей вашей базы данных.

User.all[:email]

Или только для пользователей, которые подписались или что-то в этом роде.

User.where(:subscribed => true)[:email].each do |email|
  puts "Do something with #{email}"
end

Использование User.all.map(&:email) считается плохой практикой по причинам, указанным выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...