Rails API挂载CarrierWave上传器新增版本后接口缓存报错求助
问题原因
该报错核心是CarrierWave上传器实例序列化进Rails缓存时的动态类冲突问题:
- 你给ImageUploader添加多版本规则后,CarrierWave会为每个版本动态生成匿名上传器子类,类名会带随机数字后缀(就是你报错信息里的
Uploader2293312720这类标识符) - 你用
as_json直接序列化Article对象时,image字段对应的上传器实例会被完整序列化进缓存,其中包含了这个动态生成的子类引用 - 服务器重启、进程重启或者Rails类重新加载后,旧的动态类会被销毁,新生成的动态类后缀数字会变化,从缓存反序列化时找不到旧的动态类名,就会抛出未初始化常量的错误
- 改动前没有多版本也没有图片处理逻辑时,上传器不会生成动态子类,所以序列化、反序列化都不会触发问题,加了版本规则后才会触发该故障
解决办法
以下为按优先级排序的可行方案:
- 序列化时手动指定image字段仅返回URL,不序列化整个上传器实例
这是最稳定的解决方法,修改as_json参数,显式指定image字段的输出内容,避免把整个上传器对象存入缓存:
首先给Article模型补充返回图片各版本URL的方法:
class Article < ApplicationRecord validates_presence_of :title, :intro, :body, :image, :release_date, :slug mount_uploader :image, ImageUploader # 补充该方法按需返回需要的图片版本链接 def image_url { original: image.url, thumb: image.thumb.url, big: image.big.url } end end
再修改缓存逻辑中的as_json配置:
.as_json( # 列出你需要返回的Article基础字段,注意不需要单独加image字段 only: [:id, :title, :intro, :body, :release_date, :slug], # 指定加载刚才定义的image_url方法返回值 methods: [:image_url], include: [ { related_articles: { except: [:body, :intro, :preview], methods: [:image_url] } }, { categories: { } }, { users: { except: [:password_digest, :password_reset_token, :password_reset_sent_at] } }, { external_authors: { } } ] )
- 存入缓存前手动处理image字段
如果你不想调整返回的JSON结构,也可以在缓存块结束前手动把image字段替换为纯URL字符串,避免上传器实例被序列化 - 关闭CarrierWave动态类生成(不推荐)
该方案会影响CarrierWave版本功能的正常运行,仅作为极端场景下的备选,不建议生产环境使用
内容的提问来源于stack exchange,提问作者Marius W
相关产品推荐
相关产品推荐

