やったこと
今回、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ストレージに使わないほうが良いと思っています。