【问题标题】:Rails per-request hash?Rails 每个请求的哈希?
【发布时间】:2009-03-19 00:17:14
【问题描述】:

有没有办法在 Rails 中缓存每个请求的数据?对于给定的 Rails/mongrel 请求,我有一个半昂贵的操作的结果,我想稍后在该请求中访问几次。是否有可以存储和访问此类数据的哈希?

它需要是相当全局的,并且可以从视图、控制器和库中访问,例如 Rails.cache 和 I18n。

如果需要的话,我可以给猴子打补丁。

  • Memcached 不起作用,因为它会在请求之间共享,这是我不希望的。
  • 全局变量同样不起作用,因为不同的请求会共享相同的数据,这不是我想要的。
  • 实例变量不起作用,因为我想从不同的类中访问数据。

【问题讨论】:

  • 您说您希望它在请求之间共享(项目符号 1),但您也不希望请求共享它(项目符号 2)。我想我知道你的意思,但你应该澄清一下。
  • 在项目符号 1 中我说我希望它在请求之间共享。

标签: ruby-on-rails


【解决方案1】:

试试PerRequestCache。我从 SQL 查询缓存中窃取了设计。

config/environment.rb 中配置它:

config.middleware.use PerRequestCache

然后使用它:

PerRequestCache.fetch(:foo_cache){ some_expensive_foo }

【讨论】:

  • 正如您的要点所暗示的,它不是线程安全的。我刚刚把东西直接存放在 SQL 查询缓存中。这是一个 hack,但它有效。
【解决方案2】:

还有request_store 宝石。来自文档:

将此行添加到应用程序的 Gemfile:

gem 'request_store'

并使用此代码存储和检索数据(仅限于请求):

# Set
RequestStore.store[:foo] = 0

# Get
RequestStore.store[:foo]

【讨论】:

  • gem基本解决了整个问题。我已经添加了一些使用说明,但基本上没有什么比这更多的了。
  • 您不应将此 gem 与 Thin 或 Puma 等线程服务器一起使用。
  • @Papipo 此 gem 的文档明确将自己定义为 Thread.current 的功能替代品,适用于 Thin 和 Puma 等线程服务器。
【解决方案3】:

最流行的选项之一是使用request_store gem,它允许您从代码的任何部分访问全局存储。它使用Thread.current 来存储您的数据,并负责在每次请求后清理数据。

RequestStore[:items] = []

但请注意,由于它使用 Thread.current,因此它无法在每个请求有多个线程的多线程环境中正常工作。

为了规避这个问题,我实现了一个可以在同一请求的线程之间共享的存储。叫request_store_rails,是线程安全的,用法也很相似:

RequestLocals[:items] = []

【讨论】:

    【解决方案4】:

    全局变量是邪恶的。弄清楚如何干净地将您想要的数据传递到您想要使用它的地方。

    【讨论】:

    • 这并不总是实用的。就像我提到的,Rails 有像 Rails.cache 和 I18n 这样的全局对象。
    【解决方案5】:

    你考虑过闪存吗?它使用 Session 但被自动清除。

    【讨论】:

      【解决方案6】:

      Memoisation?

      根据this railscast,它是按请求存储的。

      【讨论】:

      • 类方法的记忆将一直缓存。实例上的记忆将在该实例的生命周期内缓存。类上的过多缓存会阻塞内存。我已经删除了犯这个错误的生产盒。
      【解决方案7】:

      app/models/my_cacher.rb

      class MyCacher
        def self.result
          @@result ||= begin
            # do expensive stuff
            # and cache in @@result
          end
        end
      end
      

      ||= 语法基本上意味着“如果@@result 为nil,则执行以下操作”(即尚未设置任何内容)。只需确保开始/结束块中的最后一行返回结果即可。

      然后在您的视图/模型/任何您需要时引用的函数:

      MyCacher.result
      

      这将在请求期间缓存昂贵的操作。

      【讨论】:

      • 这将在生产模式下的应用实例(许多请求)的生命周期内被缓存。
      猜你喜欢
      • 1970-01-01
      • 2023-03-25
      • 2011-10-27
      • 1970-01-01
      • 2014-12-09
      • 1970-01-01
      • 2016-10-25
      • 2018-09-03
      • 1970-01-01
      相关资源
      最近更新 更多