こんにちは。たびたび、Rails の cache に悩まされているラクマの豊永です。
今回、Rails のキャッシュ機構で、Active Record のオブジェクトを保存すると "色々、大変なことがあるぞ" ということについて書いていきたいと思います。
ちなみにここでいうキャッシュ機構は、cache_store のことを指します。
それでは始めます。
確認環境
$ bundle exec rails --version Rails 5.2.4.3 $ mysql --version mysql Ver 14.14 Distrib 5.6.43, for osx10.13 (x86_64) using EditLine wrapper
検証
準備
テーブル作成
CREATE TABLE `pencils` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `maker_name` varchar(50) NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC
データ登録
INSERT INTO pencils VALUES (NULL, 'maker1', NOW(), NOW());
app/models/pencil.rb
class Pencil < ApplicationRecord end
config/environments/development.rb (抜粋)
config.cache_store = :memory_store
cache に保存する
$ bundle exec rails c Running via Spring preloader in process 65049 Loading development environment (Rails 5.2.4.3) irb(main):001:0> p = Pencil.last (1.3ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483 Pencil Load (0.9ms) SELECT `pencils`.* FROM `pencils` ORDER BY `pencils`.`id` DESC LIMIT 1 => #<Pencil id: 1, maker_name: "maker1", created_at: "2020-11-08 22:45:49", updated_at: "2020-11-08 22:45:49"> irb(main):002:0> Rails.cache.write('pencil1', p) => true irb(main):003:0> Rails.cache.read('pencil1') => #<Pencil id: 1, maker_name: "maker1", created_at: "2020-11-08 22:45:49", updated_at: "2020-11-08 22:45:49"> irb(main):004:0> Rails.cache.read('pencil2') => nil
クラス名を変更する (そろそろ来るぞ!)
app/models/pencil.rb を下記のように変更します。
app/models/pencil2.rb
class Pencil2 < ApplicationRecord end
保存してある cache を読み込む
irb(main):004:0> reload! Reloading... => true irb(main):005:0> Rails.cache.read('pencil1') Traceback (most recent call last): 1: from (irb):5 NameError (uninitialized constant Pencil)
はい。Pencil クラスがなくなってしまったので、ロードで失敗してしまいました。
これは、"色々、大変なことがあるぞ" の1つです。
対応方針
cacheストレージ使うときは、"安心なデータ" を入れる必要があります。
データ構造じゃない、value を入れるのが安心です。
例えば以下が "安心なデータ" と考えます。
- 数値 例: 123
- 文字列 例: あいう
配列、json、ハッシュもデータ構造が変わるときに対応を忘れないようにすれば、使って良いと思います。
Active Record のオブジェクトは、cacheストレージに保存しない方が安心です。
なぜかといえば、例えば、Railsのバージョンが変わったとき、ApplicationRecord
の内部の構造も変わり
読み込めなくなる可能性があるからです。
はい。実際にありました。
ApplicationRecord
は rails の本体に入っているため、この事態に気が付きにくいです。
また、システムが大きくなればなるほど、対応範囲の調査が大変になります(経験談)
まとめ
cacheストレージ使うときは、構造が変更される可能性が低いデータを入れましょう!!!
"安心なデータ" は、構造が変更される可能性が低いデータになります。
- 数値 例: 123
- 文字列 例: あいう
もちろん、配列、json、ハッシュなどを使ったほうがいいケースもあり、その場合は構造を変更するときに注意してください。
構造が変更される可能性があって、検知しづらいのが Active Record のオブジェクト
だと思います。
Active Record のオブジェクト
をcacheストレージに入れた方が良い場合があるかもしれませんが、
いまのところ、私は、Active Record のオブジェクト
をcacheストレージに使わないほうが良いと思っています。
それでは失礼します。