paper_trailでRailsのモデルに対する変更履歴を保存する
はじめに
特定のリソースに対して、作成や更新のたびに何が行われたのかを保存、後々で閲覧したいという要望は決して少なくないかと存じます。そうした時に便利なのが、paper_trailというgemです。
実装
PaperTrailをインストールします。
gem install 'paper_trail'
こちらのgemにはrailsのジェネレーターが付属しているので、bundle install後に実行します。履歴管理を行うのに利用するマイグレーションファイルが生成されます。
bundle exec rails g paper_trail:install
bundle exec rake db:migrate
最後に履歴管理を行いたいモデルに対して、個別にPaperTrailの利用を宣言します。
また、以前はモデルを操作したcurrent_userのidが自動的に挿入されていたのですが、現行バージョンではそれが外されております。必要に応じて、controller側でコールバックを呼び出す必要があります。
ただし、これはcurrent_userの名前を自前で変更していたりすると、機能が正しく動かないので注意が必要です。
変更履歴は上記のマイグレーションによって作成されたversionsテーブルに保存されます。has_paper_trailを宣言したモデルすべての変更履歴が、versionsテーブルに一括して追加されます。
irb(main):011:0> post = Post.create!(title: 'hoge', folder: Folder.last)
Folder Load (1.2ms) SELECT `folders`.* FROM `folders` ORDER BY `folders`.`id` DESC LIMIT 1
(0.2ms) BEGIN
Post Create (0.4ms) INSERT INTO `posts` (`title`, `folder_id`, `created_at`, `updated_at`) VALUES ('hoge', 1, '2018-08-01 13:06:49', '2018-08-01 13:06:49')
PaperTrail::Version Create (0.3ms) INSERT INTO `versions` (`item_type`, `item_id`, `event`, `created_at`) VALUES ('Post', 4, 'create', '2018-08-01 13:06:49')
(1.1ms) COMMIT
=> #<Post id: 4, title: "hoge", status: "draft", folder_id: 1, created_at: "2018-08-01 13:06:49", updated_at: "2018-08-01 13:06:49">
irb(main):012:0> post.update!(title: 'hogehoge')
(0.4ms) BEGIN
Post Update (0.9ms) UPDATE `posts` SET `title` = 'hogehoge', `updated_at` = '2018-08-01 13:06:59' WHERE `posts`.`id` = 4
PaperTrail::Version Create (0.4ms) INSERT INTO `versions` (`item_type`, `item_id`, `event`, `object`, `created_at`) VALUES ('Post', 4, 'update', '---\nid: 4\ntitle: hoge\nstatus: 10\nfolder_id: 1\ncreated_at: 2018-08-01 13:06:49.000000000 Z\nupdated_at: 2018-08-01 13:06:49.000000000 Z\n', '2018-08-01 13:06:59')
(1.1ms) COMMIT
=> true
過去の履歴を参照するためには各モデルに生えたversionsメソッドを利用します。
irb(main):013:0> post.versions
PaperTrail::Version Load (2.4ms) SELECT `versions`.* FROM `versions` WHERE `versions`.`item_id` = 4 AND `versions`.`item_type` = 'Post' ORDER BY `versions`.`created_at` ASC, `versions`.`id` ASC LIMIT 11
=> #<ActiveRecord::Associations::CollectionProxy [#<PaperTrail::Version id: 4, item_type: "Post", item_id: 4, event: "create", whodunnit: nil, object: nil, created_at: "2018-08-01 13:06:49">, #<PaperTrail::Version id: 5, item_type: "Post", item_id: 4, event: "update", whodunnit: nil, object: "---\nid: 4\ntitle: hoge\nstatus: 10\nfolder_id: 1\ncrea...", created_at: "2018-08-01 13:06:59">]>
今回はrails consoleからデータを操作したので、whodunnitがnilになっておりますね。