Подтвердить что ты не робот

Включен ActiveRecord. Укажите включенные столбцы

У меня есть профиль модели. Профиль has_one Пользователь. Пользовательская модель имеет полевую электронную почту. Когда я звоню

Profile.some_scope.includes(:user)

он вызывает

SELECT users.* FROM users WHERE users.id IN (some ids)

Но моя модель User имеет много полей, которые я не использую в рендеринге. Можно ли загружать только электронные письма от пользователей? Итак, SQL должен выглядеть как

SELECT users.email FROM users WHERE users.id IN (some ids)
4b9b3361

Ответ 1

У Rails нет возможности передать параметры запроса include. Но мы можем передать эти параметры с объявлением ассоциации под моделью.

Для сценария вам необходимо создать новую ассоциацию с моделью пользователей в модели профиля, например ниже

belongs_to :user_only_fetch_email, :select => "users.id, users.email", :class_name => "User"

только я создал еще одну ассоциацию, но он указывает только на модель пользователя. Таким образом, запрос будет,

Profile.includes(:user_only_fetch_email)

или

Profile.includes(:user_only_fetch_email).find(some_profile_ids)

Ответ 2

Если вы хотите выбрать определенные атрибуты, вы должны использовать joins, а не includes.

Из этого asciicast:

опция include действительно не работает с опцией выбора, так как мы не контролируем, как генерируется первая часть инструкции SELECT. Если вам нужен контроль над полями в SELECT, вы должны использовать объединения над include.

Использование joins:

Profile.some_scope.joins(:users).select("users.email")

Ответ 3

Вам нужна дополнительная принадлежность в модели.

Для простой ассоциации:

belongs_to :user_restricted, -> { select(:id, :email) }, class_name: 'User'

Для полиморфной ассоциации (например, :commentable):

belongs_to :commentable_restricted, -> { select(:id, :title) }, polymorphic: true, foreign_type: :commentable_type, foreign_key: :commentable_id

Вы можете выбрать любое belongs_to имя, которое вы хотите. Для приведенных выше примеров вы можете использовать их как Article.featured.includes(:user_restricted), Comment.recent.includes(:commentable_restricted) и т.д.

Ответ 4

Я хотел эту функциональность самостоятельно, поэтому, пожалуйста, используйте ее. Включите этот метод в свой класс

#ACCEPTS args в строковом формате "ASSOCIATION_NAME: COLUMN_NAME-COLUMN_NAME"

def self.includes_with_select(*m)
    association_arr = []
    m.each do |part|
      parts = part.split(':')
      association = parts[0].to_sym
      select_columns = parts[1].split('-')
      association_macro = (self.reflect_on_association(association).macro)
      association_arr << association.to_sym
      class_name = self.reflect_on_association(association).class_name 
      self.send(association_macro, association, -> {select *select_columns}, class_name: "#{class_name.to_sym}")
    end
    self.includes(*association_arr)
  end

И вы сможете вызвать как: Contract.includes_with_select('user:id-name-status', 'confirmation:confirmed-id'), и он выберет те указанные столбцы.

Ответ 5

Используя пример Моханай, вы можете сделать это:

belongs_to :user_only_fetch_email, -> { select [:id, :email] }, :class_name => "User"