我正在使用redis缓存在我的rails应用程序中获取数据。简而言之,我可以说我有两个应用程序,第一个是基于轨道4,第二个是基于轨道6。我必须在两个应用程序中使用缓存数据。
在 rails 4 应用程序中:- 我已经在rails 4 应用程序中创建了缓存,并且它成功获取了数据。
Rails.cache.fetch("test_cache"){User.last}
=> #<User id: 100973, email: "xxxx.com", encrypted_password: "$2a$10$D8aOhoSWvNWeEQE2swAX2OEVIF5H0aY8sR/fGVQ3BhU...........>
在 rails 6 应用程序中:- 但是当我想在我的rails 6 应用程序中加载相同的缓存时,会给我一个错误。
Rails.cache.fetch("test_cache"){User.last}
Traceback (most recent call last):
2: from (irb):18
1: from (irb):18:in `rescue in irb_binding'
NameError (uninitialized constant ActiveRecord::AttributeSet)
Did you mean? ActiveRecord::Attributes
然后我得出了一个解决方案,使用as_json
保存数据
Rails.cache.fetch("test_cache"){User.last.as_json}
它成功地工作并在两个应用程序上获取了数据,但是我还有一个问题,如何访问相同的model methods, associations etc etc...
。
任何建议或任何想法?
对于缓存中的非字符串值,Rails 使用Marshal.dump
(并且对于大的 Rails 也通过 Calmate 压缩它(。封送数据可以被认为是介于数据和代码之间的东西,因为它具有对类名和内部结构的引用。这就是为什么它有局限性:它只能使用相同的 ruby 版本进行解组(参见 ruby 文档(,并且应用程序应该具有相同的类。
显然,ActiveRecord::Base
轨4和轨6的结构不同,因此在编组时不兼容。
为了获得兼容性,您唯一的选择是仅缓存基本的 Ruby 类型和 PORO,它们不引用应用程序中任何不同的类。你尝试使用as_json
正是这样做的 - 存储模型的哈希表示。
但实际上第一步是再次考虑究竟要缓存什么以及为什么要缓存,有几个想法需要考虑:
- 当然,Redis/Memcache速度很快,但访问它仍然是一个数据库查询,具有相应的开销。从SQL数据库(如
User.find(primary_key_value_here)
(的简单读取几乎一样快。 - AR模型具有用于关联的缓存,您可能也有一些记忆数据,您可能会遇到这些数据停滞
- 访问非缓存关联仍会导致数据库调用
- 您最希望缓存的可能不是模型本身,而是一种更容易找到它的方法(例如,如果它是某些昂贵计算的结果(或某些派生数据。在前一种情况下,存储记录 ID 就足够了,在后一种情况下,您可以存储诸如哈希/PORO 之类的东西,其中包含所需的所有数据,例如:
hash = Rails.cache.fetch("last_registered_user"){
User.last.yield_self{|u|
{
user_id: u.id,
name: u.name,
registered_at: u.created_at,
invited_by: u.invited_by.name
}
}
}