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

如何将JSON反序列化为附带装饰器的ActiveRecord对象

问题根因

JSON是纯数据序列化格式,仅存储键值对结构的数据,不会保留Ruby对象的类信息、方法、装饰器关联关系。你直接对装饰器对象执行to_json后再JSON.parse,得到的是普通的Ruby Hash(你报错指向String类大概率是序列化/反序列化步骤操作失误,没有正确拿到解析后的Hash结构),本身不是BookDecorator类的实例,自然无法访问list_of_reviews方法。
另外你现有的BookDecorator初始化方法存在问题:SimpleDelegator的初始化需要接收被代理的对象作为参数,你当前的无参初始化写法不符合要求,需要先修正。

解决方案

步骤1:修正装饰器初始化逻辑

class BookDecorator < SimpleDelegator
  attr_accessor :list_of_reviews
  
  # 增加被装饰Book对象的入参
  def initialize(book)
    super(book)
    @list_of_reviews = []
  end

  # 可选:封装反序列化方法,简化调用
  def self.deserialize(data_hash)
    # 方式1:从数据库查询最新的Book数据(推荐,保证数据一致性)
    book = Book.find(data_hash["book_id"])
    # 方式2:无需查库,直接用序列化数据生成Book实例(适合对实时性要求不高的场景)
    # book = Book.instantiate(data_hash.except("list_of_reviews"))
    instance = new(book)
    instance.list_of_reviews = data_hash["list_of_reviews"]
    instance
  end
end

步骤2:调整序列化逻辑

序列化时需要同时保留原始Book对象的标识/属性,以及装饰器新增的扩展字段:

# 1. 生成装饰后的对象
origin_book = Book.find(1)
decorated_book = BookDecorator.new(origin_book)
decorated_book.list_of_reviews = ["内容扎实", "值得反复阅读"]

# 2. 构造可序列化的Hash结构
serialized_data = decorated_book.as_json.merge(
  book_id: decorated_book.id, # 存id供反序列化查库,如果用无查库方式可以不加
  list_of_reviews: decorated_book.list_of_reviews
)

# 3. 转JSON存入Redis
json_str = serialized_data.to_json
$redis.set("cached_book_1", json_str)

步骤3:反序列化为带装饰器的对象

# 1. 从Redis取数据
json_str = $redis.get("cached_book_1")
data_hash = JSON.parse(json_str)

# 2. 调用装饰器封装的反序列化方法直接得到目标对象
decorated_book = BookDecorator.deserialize(data_hash)

# 3. 正常调用装饰器方法
puts decorated_book.list_of_reviews # => ["内容扎实", "值得反复阅读"]
# 也可以正常调用原始Book对象的所有属性和方法
puts decorated_book.author_id

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 19:45:04