如何将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
相关产品推荐
相关产品推荐

