如何在请求之间缓存实例变量?

And*_*vey 2 ruby-on-rails

Miniprofiler指示我的Rails应用程序在每个页面上进行大量数据库查询。问题似乎是布局中包含的页首横幅模块。

该应用程序如下所示:

#application_controller.rb
before_filter :initialize_leaderboard

def initialize_leaderboard
  @leaderboard_users ||= User.monthly_leaderboard
end

#user.rb

def self.monthly_leaderboard
  User.includes(:events).sort_by(&:events_last_month).reverse
end

def events_last_month
  @events_last_month ||= events.where( created_at: Date.today.beginning_of_month-1.month..Date.today.end_of_month-1.month ).size
end

#application.html.erb
...
<% unless @leaderboard_users.blank? %>
  <% cache ["sidebar_leaderboard", @leaderboard_users] do %>
    ...html
  <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

在日志和miniprofiler输出中,我看到了events_last_month每个用户的查询。这不是所希望的,并且让我质疑我对所有这些工作原理的理解。我可以这样吗?

  1. 该视图已被缓存,因此,假设以前(最近)已查看过特定的Leaderboard_user,则应从缓存中显示其详细信息。
  2. 因此,许多events_last_month查询必须源自initialize_leaderboardapplication_controller.rb中的 方法。但是,我知道使用||=User.monthly_leaderboard为后续请求缓存方法的响应 。为什么在每个页面视图中都调用它?

Mat*_*ver 5

||=将记住来自的非虚假结果User.monthly_leaderboard。该数据将在ApplicationController实例的生命周期内保留。为每个请求创建一个新实例。

从文档:

当您的应用程序接收到请求时,路由将确定要运行的控制器和动作,然后Rails创建该控制器的实例,并以与动作相同的名称运行该方法。

如果您希望在请求之间缓存(有时过期并重新查询)该实例变量的值,则需要显式利用外部缓存或寻找另一个位置来存储在请求(例如会话)中持久存在的值(如果结果是)相对较小,并且特定于用户会话。

如果该值应该被查询一次并一直保持到重新启动Web服务器,则可以考虑在初始化程序中查询该数据,并将结果存储在该过程的整个生命周期中都将持续存在的位置。