Rails + Trix + Stimulusで作るドキュメント管理ツール — 編集履歴編

Kota Miyake
Ruffnote
Published in
9 min readOct 25, 2018
Photo by Tanner Mardis on Unsplash

前回はscaffoldを使ってベースとなるドキュメントの閲覧、作成、更新、削除の機能を実装しました。

はじめに設定したゴールを確認してみましょう。

  • ✔ドキュメントを閲覧、作成、更新、削除できる
  • 編集履歴を管理できる
  • 編集前後で差分を表示できる

今回は「編集履歴を管理できる」という部分を実装していきたいと思います。

ドキュメントを管理する上で編集履歴を管理できることはとても重要です。

ドキュメントを書くのは人間であり、往々にしてミスや勘違いなどによる間違いが発生します。

その時に編集履歴が管理されていれば、以前の状態を確認したり、また以前の状態に戻したりすることができます。

PaperTrail vs Audited

Rubyでは編集履歴を管理するための便利なgemが用意されています。その中で最も有名なgemがPaperTrailAuditedです。

下記の記事では、それぞれの違いについて3つの質問から答えています。

The battle for auditing and versioning in Rails — Audited vs Paper Trail

この記事ではいくつかの違いを紹介した上で、状況によって環境に適した方を自分たちで選択する必要があると締めくくっています。

簡単にまとめると違いは以下のようなものがあるようです。

  • Auditedではdeviseなどの認証システムが用意されている場合は自動でユーザーと関連付けて編集履歴を残してくれる。PaperTrailは自身で設定する処理を書く必要がある。
  • どちらも作成、更新、削除の履歴を記録することができ、またその履歴から復元する方法も用意されてる。
  • PaperTrailでは編集履歴を保存する条件を設定することができる。Auditedでも同じような処理を書くことはできる。

Auditedは「Active Record User Stamping」で主に特定ユーザー追いかけ用、Paper Trailは「Active Record Versioning Area」で主に関数やメソッドなどの領域ベースで時間軸に沿った変更を追うときに、と使い分ける感じです。

週刊Railsウォッチ(20170721)ActiveStorageは5.2で正式導入、Onigmoの脆弱性が修正、この夏読みたい名作Ruby本ほか

特定のユーザーを追跡するという要件は、今のところ特にないので今回はPaperTrailを使っていきたいと思います。(PaperTrailでもユーザーと変更を関連付けることはできるので。

編集履歴を管理できる

READMEを参考にしながらPaperTrailを導入します。

# Gemfile
gem 'paper_trail'

--with-changes オプションをつけることで、データ量は増えてしまいますが、差分を表示する時に changeset メソッドで簡単に編集前後のデータを取得できるようになります。

$ bundle exec rails generate paper_trail:install --with-changes
$ bin/rails db:migrate

データベースの準備が整ったので、あとはモデルでPaperTrailを使うことを宣言するだけです。

# app/models/document.rb
class Document < ApplicationRecord
has_paper_trail
end

ではさっそく新たに記事を作成して編集履歴が保存されるか確認してみましょう。

irb(main):004:0> Document.create(name: 'PaperTrailを導入する', content: 'PaperTrailを使うことで編集履歴を残すことができます。')(0.3ms)  BEGINDocument Create (1.7ms)  INSERT INTO `documents` (`name`, `content`, `created_at`, `updated_at`) VALUES ('PaperTrailを導入する', 'PaperTrailを使うことで編集履歴を残すことができます。', '2018-10-24 01:28:53', '2018-10-24 01:28:53')PaperTrail::Version Create (0.3ms)  INSERT INTO `versions` (`item_type`, `item_id`, `event`, `created_at`, `object_changes`) VALUES ('Document', 2, 'create', '2018-10-24 01:28:53', '---\nid:\n- \n- 2\nname:\n- \n- PaperTrailを導入する\ncontent:\n- \n- PaperTrailを使うことで編集履歴を残すことができます。\ncreated_at:\n- \n- 2018-10-24 01:28:53.000000000 Z\nupdated_at:\n- \n- 2018-10-24 01:28:53.000000000 Z\n')(0.4ms)  COMMIT=> #<Document id: 2, name: "PaperTrailを導入する", content: "PaperTrailを使うことで編集履歴を残すことができます。", created_at: "2018-10-24 01:28:53", updated_at: "2018-10-24 01:28:53">irb(main):005:0> Document.last.versionsDocument Load (0.4ms)  SELECT  `documents`.* FROM `documents` ORDER BY `documents`.`id` DESC LIMIT 1PaperTrail::Version Load (0.9ms)  SELECT  `versions`.* FROM `versions` WHERE `versions`.`item_id` = 2 AND `versions`.`item_type` = 'Document' ORDER BY `versions`.`created_at` ASC, `versions`.`id` ASC LIMIT 11=> #<ActiveRecord::Associations::CollectionProxy [#<PaperTrail::Version id: 1, item_type: "Document", item_id: 2, event: "create", whodunnit: nil, object: nil, created_at: "2018-10-24 01:28:53", object_changes: "---\nid:\n- \n- 2\nname:\n- \n- PaperTrailを導入する\ncontent:...">]>irb(main):006:0> Document.last.versions.last.changesetDocument Load (0.4ms)  SELECT  `documents`.* FROM `documents` ORDER BY `documents`.`id` DESC LIMIT 1PaperTrail::Version Load (0.4ms)  SELECT  `versions`.* FROM `versions` WHERE `versions`.`item_id` = 2 AND `versions`.`item_type` = 'Document' ORDER BY `versions`.`created_at` DESC, `versions`.`id` DESC LIMIT 1Document Load (0.3ms)  SELECT  `documents`.* FROM `documents` WHERE `documents`.`id` = 2 LIMIT 1=> {"id"=>[nil, 2], "name"=>[nil, "PaperTrailを導入する"], "content"=>[nil, "PaperTrailを使うことで編集履歴を残すことができます。"], "created_at"=>[nil, Wed, 24 Oct 2018 01:28:53 UTC +00:00], "updated_at"=>[nil, Wed, 24 Oct 2018 01:28:53 UTC +00:00]}

無事、編集履歴が残っていることを確認できました。

✔編集履歴を管理できる

編集履歴の一覧を表示する

せっかくなので保存した編集履歴の一覧を表示したいと思います。

簡単に見た目を整えたいと思うので、bootstrapを導入します。

bootstrap-rubygemを使うことで簡単にRailsにbootstrapを導入することができます。

Rails 5.1以降、デフォルトでjQueryがインストールされない、かつbootstrapはjQueryに依存しているため、 jquery-rails を合わせて導入します。

# Gemfile
gem 'bootstrap', '~> 4.1.3'
gem 'jquery-rails'

あとはREADMEに従ってjsとcssを設定していきます。

# app/assets/stylesheets/application.scss
@import "bootstrap";
# app/assets/javascripts/application.js
//= require jquery3
//= require popper
//= require bootstrap-sprockets

導入が終わったら軽く見た目を整えてみました。

これでどのような変更があったのか表示すれば立派なドキュメント管理ツールになりますね!(なりません

次回は「編集前後で差分を表示できる」機能を実装する前にtrixを導入してドキュメントにスタイリングができるようにしたいと思います。

ここまでのコードは以下のリポジトリで確認できます。

乞うご期待!

--

--