我在我的Rails应用程序中使用Devise进行身份验证。我想在我的一些控制器中加载一些用户相关模型。像这样:
class TeamsController < ApplicationController
def show
@team = Team.includes(:members).find params[:id]
current_user.includes(:saved_listings)
# normal controller stuff
end
end
我怎样才能做到这一点?
答案 0 :(得分:21)
我遇到了同样的问题,尽管每个人都说没有必要这样做,但我发现就像你一样。所以这对我有用:
# in application_controller.rb:
def current_user
@current_user ||= super && User.includes(:saved_listings).find(@current_user.id)
end
请注意,这将加载所有控制器中的关联。对于我的用例,这正是我需要的。如果你真的只想在某些控制器中使用它,你将不得不再调整它。
这也会调用User.find
两次,但是查询缓存不应该是一个问题,并且因为它可以防止大量额外的数据库命中,所以它仍然是性能提升。
答案 1 :(得分:9)
覆盖User
模型中的serialize_from_session
。
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
然而,这将迫切加载所有请求。
答案 2 :(得分:1)
我想补充一下我认为是更好的解决方案。如评论中所述,现有解决方案可能会因find
请求而两次进入您的数据库。相反,我们可以使用ActiveRecord::Associations::Preloader
来利用Rails的工作来加载关联:
def current_user
@current_user ||= super.tap do |user|
::ActiveRecord::Associations::Preloader.new.preload(user, :saved_listings)
end
end
这将重新使用内存中的现有模型,而不是再次联接和查询整个表。
答案 3 :(得分:-3)
为什么不在模型上使用default_scope呢?
像这样:Class User < ActiveRecord::Base
...
default_scope includes(:saved_listings)
...
end