You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 5升级至6.1后本地缓存异常:页面重载需重启服务器

Rails 6.1 本地缓存偶发异常:Location can't be referred to

生产环境基于MemCachier实现Rails缓存,将Rails版本从5升级至6.1后,本地环境出现偶发异常:重载使用缓存的页面时,偶尔会触发ActionView::Template::Error (Location can't be referred to),必须重启服务器才能恢复,且该问题并非每次刷新都会出现。

相关代码片段

局部视图 _locations_data.html.erb

<% cache(cache_view_key, skip_digest: true, :expires_in => location.cached_start_date) do %>

<% end %>

Location模型代码

def cached_start_date
  cached_location_start_date
  # 其他使用缓存数据的业务代码
end

def cached_location_start_date
    puts "ID -> #{id}" # 可正常打印
    puts "Cache Object -> #{Rails.cache.inspect}" # 可正常打印:Cache Object -> #<ActiveSupport::Cache::MemoryStore entries=11, size=15971, options={:compress=>false}>
    puts "Cache -> #{Rails.cache.read("location_#{id}_start_date")}" # 此处触发错误:Location can't be referred to

    Rails.cache
         .fetch("location_#{id}_start_date") do
      Location.select(:start_date).find(id)
    end
end

development.rb配置

config.cache_classes = false

if Rails.root.join('tmp', 'caching-dev.txt').exist?
  config.action_controller.perform_caching = true
  config.action_controller.enable_fragment_cache_logging = true

  config.cache_store = :memory_store
  config.public_file_server.headers = {
    'Cache-Control' => "public, max-age=#{1.days.to_i}"
  }
else
  config.action_controller.perform_caching = false

  config.cache_store = :memory_store
end

问题分析与解决办法

  • 核心原因:开发环境类重载导致缓存实例失效
    开发环境中config.cache_classes = false,Rails会在代码变更时自动重新加载类文件。当缓存中存储的是Location模型实例时,类重载后旧实例对应的类定义已失效,此时尝试访问缓存中的旧实例就会触发"can't be referred to"错误。

  • 针对性解决措施

    1. 缓存原始数据而非模型实例:不要直接缓存查询返回的模型对象,提取需要的字段值缓存,避免类重载带来的实例失效问题:
      Rails.cache.fetch("location_#{id}_start_date") do
        Location.select(:start_date).find(id).start_date
      end
      
    2. 序列化缓存对象:将模型实例序列化为JSON字符串存储,读取时再反序列化,隔绝类重载的影响:
      # 存储时
      Rails.cache.fetch("location_#{id}_start_date") do
        Location.select(:start_date).find(id).to_json
      end
      # 读取时
      JSON.parse(Rails.cache.read("location_#{id}_start_date"))["start_date"]
      
    3. 类重载时清理缓存:通过Rails的to_prepare回调,在类重新加载时自动清理相关缓存,避免旧实例残留:
      # 在config/initializers/cache_cleanup.rb中添加
      Rails.application.config.to_prepare do
        Rails.cache.delete_matched("location_*_start_date")
      end
      

内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:07:22