在我的Car模型的
JSON表示中,我包含了一个昂贵方法的输出:
#car.rb def as_json(options={}) super(options.merge(methods: [:some_expensive_method])) end
我有一个标准的索引操作:
#cars_controller.rb respond_to :json def index respond_with(Car.all) end
我还在其他地方使用汽车的JSON表示,如下所示:
#user_Feed.rb def Feed_contents Horse.all + Car.all end #user_Feeds_controller.rb respond_to :json def index respond_with(UserFeed.Feed_contents) end
因为汽车的JSON表示在多个地方使用,我希望它自己缓存,使用car.cache_key作为自动过期的缓存键.
这就是我目前正在做的事情:
#car.rb def as_json(options={}) Rails.cache.fetch("#{cache_key}/as_json") do super(options.merge(methods: [:some_expensive_method])) end end
将缓存代码放在as_json中是不正确的,因为缓存不是as_json的可复制性的一部分.这样做的正确方法是什么?我正在使用Rails 3.2.15.
解决方法
我先说我赞赏这个问题的努力.你会发现很难找到一个对软件设计更有兴趣的人 – 包括小方法在一个抽象层面做一件事 – 比我更好.
但是,我不得不说,在这个问题上,我实际上反对这个问题的前提.我认为你的as_json是最好的方式.
最重要的是将客户与实现脱钩. Car#as_json的客户唯一需要知道的是返回值是Car的JSON表示.并且as_json做了那件事并做得很好.缓存和/或提取是一个应该保留在方法内部的实现细节,它是一个与该任务不可分割的细节.
换句话说,就像说任何带有if语句的方法都是“不正确”,因为它做了两件事.当然这不是真的.在这两种情况下(使用if和使用Rails.cache.fetch),方法实现是一些原子操作,其结果基于条件.
这是可以采用两种方式之一的一件事,这与两件事情不同.
同时,我不得不同意@ severin的回应.它当然会工作,但您现在已将您的视图与实现细节相结合.什么,当然不是你的观点,应该对缓存方法有任何想法,甚至涉及缓存.在我看来,你现在已经用这种方法泄露了抽象.也许这没关系,但既然我们正在谈论做事的“正确方法”……
所以我说保持原样.但我相信这是一个很好的问题.