Включен 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)
Ответы
Ответ 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"