如何急切加载与current_user的关联?

Dav*_*ite 15 activerecord ruby-on-rails eager-loading devise ruby-on-rails-3

我在我的Rails应用程序中使用Devise进行身份验证.我想在我的一些控制器中加载一些用户相关模型.像这样的东西:

class TeamsController < ApplicationController

  def show
    @team = Team.includes(:members).find params[:id]
    current_user.includes(:saved_listings)

    # normal controller stuff
  end
end
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

Thi*_*ilo 23

我遇到了同样的问题,尽管每个人都说没有必要这样做,但我发现就像你一样.这对我有用:

# in application_controller.rb:
def current_user
  @current_user ||= super && User.includes(:saved_listings).find(@current_user.id)
end
Run Code Online (Sandbox Code Playgroud)

请注意,这将加载所有控制器中的关联.对于我的用例,这正是我需要的.如果你真的只想在某些控制器中使用它,你将不得不进一步调整它.

这也会调用User.find两次,但是查询缓存不应该是一个问题,并且因为它可以防止大量额外的数据库命中,所以它仍然是性能提升.


xHo*_*uet 11

我想添加我认为更好的解决方案。如评论中所述,现有解决方案可能会根据find请求两次访问您的数据库。相反,我们可以ActiveRecord::Associations::Preloader利用 Rails 解决加载关联的工作:

def current_user
  @current_user ||= super.tap do |user|
    ::ActiveRecord::Associations::Preloader.new.preload(user, :saved_listings)
  end
end
Run Code Online (Sandbox Code Playgroud)

这将重用内存中的现有模型,而不是再次连接和查询整个表。

  • 这是迄今为止最好的答案,谢谢。您还可以创建一个方便的方法,使其对被调用者显式显示。def current_user_with(includes) @current_user_with ||= current_user.tap do |user| ::ActiveRecord::Associations::Preloader.new.preload(用户, 包含) end end (2认同)

Vik*_*ary 10

serialize_from_sessionUser模型中覆盖.

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
Run Code Online (Sandbox Code Playgroud)

但是,这将迫切需要加载所有请求.

  • 上面 Thilo 当前选择的答案导致了更多的查询。如果目的是在 current_user 中急切加载关联模型以减少查询数量,则覆盖此答案中演示的类方法是可行的方法。 (2认同)