Как вызывать загрузку ассоциаций с current_user?
Я использую Devise для аутентификации в моем приложении Rails. Я бы хотел загрузить некоторые из моделей, связанных с пользователями, в некоторых моих контроллерах. Что-то вроде этого:
class TeamsController < ApplicationController
def show
@team = Team.includes(:members).find params[:id]
current_user.includes(:saved_listings)
# normal controller stuff
end
end
Как я могу это достичь?
Ответы
Ответ 1
Я столкнулся с той же проблемой, и хотя все говорят, что нет необходимости делать это, я обнаружил, что есть, как и вы. Так это работает для меня:
# in application_controller.rb:
def current_user
@current_user ||= super && User.includes(:saved_listings).find(@current_user.id)
end
Обратите внимание, что это будет загружать ассоциации во всех контроллерах. Для моего случая использования, именно то, что мне нужно. Если вы действительно хотите это только в некоторых контроллерах, вам придется еще немного настроить его.
Это также вызовет User.find
дважды, но с кешированием запросов это не должно быть проблемой, и поскольку оно предотвращает ряд дополнительных удалений БД, оно по-прежнему является усилением производительности.
Ответ 2
Переопределите serialize_from_session
в вашей User
модели.
class User
devise :database_authenticatable
def self.serialize_from_session key, salt
record = where(id: key).eager_load(:saved_listings, roles: :accounts).first
record if record && record.authenticatable_salt == salt
end
end
Это, однако, будет загружать все запросы.
Ответ 3
Я хотел добавить то, что я считаю лучшим решением. Как отмечено в комментариях, существующие решения могут дважды поразить вашу БД с помощью запроса find
. Вместо этого мы можем использовать ActiveRecord::Associations::Preloader
чтобы использовать работу Rails вокруг ассоциаций загрузки:
def current_user
@current_user ||= super.tap do |user|
::ActiveRecord::Associations::Preloader.new.preload(user, :saved_listings)
end
end
Это позволит повторно использовать существующую модель в памяти вместо того, чтобы снова объединять и запрашивать всю таблицу.
Ответ 4
Почему бы не сделать это с помощью default_scope на модели?
так:
Class User < ActiveRecord::Base
...
default_scope includes(:saved_listings)
...
end