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

发布于 2024-11-27 11:41:35 字数 314 浏览 0 评论 0原文

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

class TeamsController < ApplicationController

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

    # normal controller stuff
  end
end

我怎样才能实现这个目标?

I'm using Devise for authentication in my Rails app. I'd like to eager load some of a users associated models in some of my controllers. Something like this:

class TeamsController < ApplicationController

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

    # normal controller stuff
  end
end

How can I achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

弥繁 2024-12-04 11:41:35

我遇到了同样的问题,虽然每个人都一直说没有必要这样做,但我发现有必要这样做,就像你一样。所以这对我有用:

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

请注意,这将加载所有控制器中的关联。对于我的用例,这正是我所需要的。如果您确实只希望在某些控制器中使用它,则必须对此进行更多调整。

这还将调用 User.find 两次,但对于查询缓存来说这应该不是问题,并且由于它可以防止大量额外的数据库命中,因此仍然可以提高性能。

I ran into the same issue and although everyone keeps saying there's no need to do this, I found that there is, just like you. So this works for me:

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

Note that this will load the associations in all controllers. For my use case, that's exactly what I need. If you really want it only in some controllers, you'll have to tweak this some more.

This will also call User.find twice, but with query caching that shouldn't be a problem, and since it prevents a number of additional DB hits, it still is a performance gain.

情深缘浅 2024-12-04 11:41:35

覆盖 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

然而,这将立即加载所有请求。

Override serialize_from_session in your User model.

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

This will however, eager load on all requests.

夏尔 2024-12-04 11:41:35

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

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

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

I wanted to add what I think is a better solution. As noted in comments, existing solutions may hit your DB twice with the find request. Instead, we can use ActiveRecord::Associations::Preloader to leverage Rails' work around loading associations:

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

This will re-use the existing model in memory instead of joining and querying the entire table again.

失去的东西太少 2024-12-04 11:41:35

为什么不在模型上使用 default_scope 来实现呢?

像这样:

Class User  < ActiveRecord::Base
  ...
  default_scope includes(:saved_listings)
  ...
end

Why not do it with default_scope on the model?

like so:

Class User  < ActiveRecord::Base
  ...
  default_scope includes(:saved_listings)
  ...
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文