Rails: как упростить «.select(:my_field).map(

#ruby-on-rails #ruby-on-rails-3 #activerecord

#ruby-on-rails #ruby-on-rails-3 #activerecord

Вопрос:

Чтобы получить номера счетов выбранных заданий, я делаю:

 Job.where(...).map(amp;:invoice_number)
  

Поскольку номера счетов -это все, что мне нужно, я подумал добавить select(:invoice_number) (я предполагаю, что таким образом SQL-запрос становится более эффективным):

 Job.where(...).select(:invoice_number).map(amp;:invoice_number)
  

Есть ли лучший способ сделать то же самое? ( .select(:invoice_number).map(amp;:invoice_number) часть кажется мне неэффективной)

Ответ №1:

Вы всегда могли бы использовать select_values . Что-то похожее на:

 Job.connection.select_values(Job.where(...).select(:invoice_number).to_sql)
  

Это позволяет избежать создания экземпляров объектов ActiveRecord.

Комментарии:

1. Увлекательно… есть идеи, действительно ли это более эффективно, чем исходный код poster?

Ответ №2:

Я знаю, что этот вопрос довольно старый, но на случай, если кто-нибудь еще проверит это, этого можно достичь с помощью pluck (http://apidock.com/rails/ActiveRecord/Calculations/pluck ). Согласно http://edgeguides.rubyonrails.org/active_record_querying.html#pluck « pluck позволяет заменить код типа: Client.select(:id).map(amp;:id) на Client.pluck(:id) «

Комментарии:

1. Сейчас абсолютно верно, но только начиная с версии 3.2, которая была выпущена через некоторое время после первоначального вопроса (в начале 2012). Если вы по какой-то причине застряли при работе с устаревшими Rails, вам понадобится другой метод.

Ответ №3:

Хотелось бы, чтобы было доказано обратное, но.. Я не думаю, что это возможно

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

Ответ №4:

Вы можете использовать GROUP_CONCAT.

 invoice_numbers = Job.where(...).select('group_concat(invoice_number) as invoice_numbers').
                    first.invoice_numbers.split(',').map(amp;:to_i)
  

Этот подход слишком длинный и не очень очевидный, но он будет выполняться быстрее, чем

 Job.where(...).select(:invoice_number).map(amp;:invoice_number)