2016-03-21 5 views
1

В боковой панели я показываю только что созданные профили пользователей. Профиль belongs_to пользователь и пользователь has_one_profile. Я понял, что я использую только 3 столбца из таблицы профилей, поэтому было бы лучше использовать pluck. У меня также есть link_to user_path(profile.user) в частичном, так что я должен сказать, кто такой пользователь. На данный момент я использую includes, но мне не нужна вся таблица пользователей. Поэтому я использую многие столбцы как из таблицы пользователя, так и из профиля.rails4 pluck with order and limit

Как я могу оптимизировать это с вырыванием? Я попробовал несколько версий, но всегда получал некоторую ошибку (большую часть времени profile.user не определен).

Мой текущий код:

def set_sidebar_users 
    @profiles_sidebar = Profile.order(created_at: :desc).includes(:user).limit(3) if user_signed_in? 
end 

create_table "profiles", force: :cascade do |t| 
    t.integer "user_id",  null: false 
    t.string "first_name", null: false 
    t.string "last_name", null: false 
    t.string "company",  null: false 
    t.string "job_title", null: false 
    t.string "phone_number" 
    t.text  "description" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.string "avatar" 
    t.string "location" 
end 
+0

Вы пробовали что-то вроде 'Profile.order (created_at:: по убыванию) .limit (3) .pluck (: 'users.name') '? Другим возможным ответом может быть сделать ваш первый запрос (без включений), а затем сделать '@ profiles_sidebar.users.pluck (: username)'. Я также нашел два потока, которые могли бы помочь вам в этом вопросе: [this] (http://stackoverflow.com/a/18131149/2929693) и [this] (http://stackoverflow.com/a/26538974/2929693) , –

+0

Я думаю, вам не нужно использовать здесь. Если вы хотите с нетерпением загружать ассоциацию + загружать выбранные столбцы, тогда есть способ сделать это. Во-вторых, если вам нужны только выбранные clumns из обеих таблиц, просто используйте объединения, а не include. lemme написать ответ –

ответ

4

Хорошо давайте объясним три различных способа сделать то, что вы ищете.

Прежде всего, существует разница в includes и joins Включает в себя только загруженную нагрузку ассоциацию со всеми указанными столбцами для ассоциаций. Это не позволяет вам запрашивать или выбирать несколько столбцов из обеих таблиц. Это то, что делают joins. Это позволяет вам запрашивать обе таблицы и выбирать столбцы по вашему выбору.

def set_sidebar_users 
    @profiles_sidebar = Profile.select("profiles.first_name,profiles.last_name,profiles.id,users.email as user_email,user_id").joins(:user).order("profile.created_at desc").limit(3) if user_signed_in? 
end 

Это возвратит вас Profiles отношение, которое имеет все столбцы предоставленных вами в select пункте. Вы можете получить их так же, как и для объекта профиля. e-g

@profiles_sidebar.first.user_email предоставит вам адрес электронной почты для этого профиля.

Этот подход лучше всего, если вы хотите запросить несколько таблиц или хотите выбрать несколько столбцов из обеих таблиц.

2.Pluck

def set_sidebar_users 
    @profiles_sidebar = Profile.order(created_at: :desc).includes(:user).limit(3).pluck("users.email,profiles.first_name") if user_signed_in? 
end 

Ливер просто используется, чтобы получить столбцы из нескольких ассоциаций, но это не позволяет использовать возможности ActiveRecord. Он просто возвращает вам массив выбранных столбцов в том же порядке. Как и в первом примере, вы можете получить пользователя для объекта профиля с @profiles_sidebar.first.user Но с вырывом вы не можете, потому что это просто простой массив. Вот почему большинство ваших решений вызывает ошибку profile.user is not defined

  1. Ассоциация с выбранными столбцами.

Теперь это вариант три. В первом решении вы можете получить несколько столбцов на обеих таблицах и использовать мощность ActiveRecord, но он не хочет загружать ассоциации. Так он все равно будет стоить N + 1 запросов, если цикл через ассоциацию на возвращенном результате, как @profiles_sidebar.map(&:user)

Так что, если вы хотите использовать includes но хотим использовать выбранные столбцы, то вы должны иметь новую ассоциацию с выбранными столбцами и назвать эту ассоциацию , е-г В profile.rb

belongs_to :user_with_selected_column,select: "users.email,users.id" 

Теперь вы можете включить его в коде выше

def set_sidebar_users 
    @profiles_sidebar = Profile.order(created_at: :desc).includes(:user_with_selected_column).limit(3) if user_signed_in? 
end 

Теперь это нетерпеливые пользователи нагрузки, но будет выбрать только адрес электронной почты и идентификатор пользователя. Более подробную информацию можно найти на ActiveRecord includes. Specify included columns

UPDATE

Как вы спросили о преимуществах для срывать так давайте объяснить. Как вы знаете, pluck возвращает вам простой массив. Таким образом, он не создает экземпляр объекта ActiveRecord, он просто возвращает вам данные, возвращенные из базы данных. Так что pluck лучше всего использовать, где вам не нужны объекты ActiveRecord, а просто для отображения возвращенных данных в табличной форме. Select возвращает вам отношения, чтобы вы могли запросить его или вызвать методы модели в своих экземплярах. Так что, если мы Итоги его можно сказать срывать для модельных значений, выберите для модели объектов

Дополнительная информация может быть найдена на http://gavinmiller.io/2013/getting-to-know-pluck-and-select/

+0

Хорошее объяснение Qaisar. Еще один вопрос: главный пункт pluck - это вернуть только нужные столбцы. Я знаю это. Но здесь 'select', похоже, делает то же самое. Итак, каково конкурентное преимущество, чтобы вырвать все остальное? Например: 'Profile.select (" profiles.first_name, profiles.last_name, profiles.id, users.email as user_email, user_id ")' vs 'Profile.pluck (" profiles.first_name, profiles.last_name, profiles.id, users.email as user_email, user_id ")' –

+1

Я добавлю плюсы и минусы в ответ для дальнейшего использования –