Railsでカラムをシリアライズする
はじめに
単一のattributeに配列を入れたい、という要望は意外と多いかと思います。それは設計ミスだから云々、指摘を受けることも多いかとは存じますが、それでも入れたいものは入れたいのです。そういった時にRailsではserializeメソッドを利用します。
実装
シリアライズしたいカラムは以下の通り定義します。
シリアライズはデータをYAML(もしくはJSON)の文字列として扱うことで実現されます。なのでカラムはテキスト型として作成しています。より大きな配列を想定している場合は、MEDIUMTEXTやLOGTEXTを利用することで対応します。
モデルの定義は以下の通りです。
これでFolder#sequenceに対するシリアライズが定義されました。
irb(main):001:0> Folder.new
(0.8ms) SET NAMES utf8, @@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
=> #<Folder id: nil, name: nil, created_at: nil, updated_at: nil, ancestry: nil, sequence: []>
irb(main):002:0> Folder.create!(name: 'bar', sequence: ['1st', '2nd', '3rd'])
(0.5ms) BEGIN
Folder Create (0.7ms) INSERT INTO `folders` (`name`, `created_at`, `updated_at`, `sequence`) VALUES ('bar', '2018-08-13 06:35:41', '2018-08-13 06:35:41', '---\n- 1st\n- 2nd\n- 3rd\n')
(0.9ms) COMMIT
=> #<Folder id: 2, name: "bar", created_at: "2018-08-13 06:35:41", updated_at: "2018-08-13 06:35:41", ancestry: nil, sequence: ["1st", "2nd", "3rd"]>
irb(main):003:0> Folder.last.sequence
Folder Load (0.7ms) SELECT `folders`.* FROM `folders` ORDER BY `folders`.`id` DESC LIMIT 1
=> ["1st", "2nd", "3rd"]
注意すべきは配列に入れられる値が、任意の型であるということです。
irb(main):005:0> Folder.create!(name: 'bar', sequence: [1, 2, 3])
(0.6ms) BEGIN
Folder Create (0.9ms) INSERT INTO `folders` (`name`, `created_at`, `updated_at`, `sequence`) VALUES ('bar', '2018-08-13 06:38:17', '2018-08-13 06:38:17', '---\n- 1\n- 2\n- 3\n')
(1.3ms) COMMIT
=> #<Folder id: 3, name: "bar", created_at: "2018-08-13 06:38:17", updated_at: "2018-08-13 06:38:17", ancestry: nil, sequence: [1, 2, 3]>
irb(main):006:0> Folder.last.sequence
Folder Load (0.6ms) SELECT `folders`.* FROM `folders` ORDER BY `folders`.`id` DESC LIMIT 1
=> [1, 2, 3]
戻り値も元の型で戻ってくる為、利用するにあたっては便利である一方、取り扱いには十分に注意するべきかと存じます。