Rails + Trix + Stimulusで作るドキュメント管理ツール — 差分表示編
いよいよ最初に掲げた最後のゴールを実装です。
今までのおさらい。
- Rails + Trix + Stimulusで作るドキュメント管理ツール — 導入編 — Ruffnote — Medium
- Rails + Trix + Stimulusで作るドキュメント管理ツール — 編集履歴編 — Ruffnote — Medium
- Rails + Trix + Stimulusで作るドキュメント管理ツール — Trix導入編 — Ruffnote — Medium
今日は「編集前後で差分を表示できる」という機能を実装していきたいと思います。
ただ差分を表示するだけでは編集履歴を管理できるとはいえないので、以前のバージョンに戻すこともできるようにしたいと思います。
では、まずは差分を表示できるようにしたいと思います。
差分を表示するライブラリにはdiffyがありますが、今回はHTMLが含まれるコンテンツの差分を表示したいので、別のライブラリを使用します。
r7kamura/markdiff: Rendered Markdown differ.
READMEに従って使ってみましょう。
まずはgemをインストールします。
# Gemfile
gem 'markdiff'
それから編集履歴の差分を表示するためにルーティングやコントローラー、ビューなど諸々のファイルを用意します。
# config/routes.rb
resources :documents do
resources :versions, only: %i[show], module: :documents
end# app/controllers/documents/versions_controller.rb
# frozen_string_literal: trueclass Documents::VersionsController < ApplicationController
def show
@document = Document.find(params[:document_id])
@version = @document.versions.find(params[:id])
end
end# app/views/documents/versions/show.html.erb
<div class="row justify-content-md-center">
<div class="col-8 p-4">
<div class="d-flex justify-content-between mb-3">
<%= link_to "\"#{@document.name}\"へ戻る", document_path(@document) %>
</div>
<h1 class="font-weight-bold mb-4">
差分を表示する
</h1>
<% @version.changeset.keys.select { |key| %w[name content].include?(key) }.each do |key| %>
<div class="mb-4">
<h3 class=font-weight-bold">
<%= Document.human_attribute_name(key) %>
</h3>
<div>
<%= raw Markdiff::Differ.new.render(*@version.changeset[key]) %>
</div>
</div>
<% end %>
</div>
</div>
量が多くてちょっと見辛いですが、こちらを実装すると以下のような表示になります。
これだとちょっとわかりにくいのでスタイルを追加してみます。
それっぽくなっていますが、差分の取れ方が若干不安定なようです。
この辺はmarkdiffの実装を見ながら調整が必要です。
これだと変更後の内容が分かりづらいので、変更後の内容を表示するページを用意します。
それに伴いルーティングも変更したいと思います。
# config/routes.rb
resources :documents do
resources :versions, only: %i[show], module: :documents
resources :changes, only: %i[show], module: :documents
end# app/views/documents/versions/show.html.erb
<div class="row justify-content-md-center">
<div class="col-8 p-4">
<div class="d-flex justify-content-between mb-3">
<%= link_to "\"#{@document.name}\"へ戻る", document_path(@document) %>
</div>
<h1 class="font-weight-bold mb-4">
このバージョンを表示する
</h1>
<% @version.changeset.keys.select { |key| %w[name content].include?(key) }.each do |key| %>
<div class="mb-4">
<h3 class=font-weight-bold">
<%= Document.human_attribute_name(key) %>
</h3>
<div>
<%= raw @version.changeset[key].last %>
</div>
</div>
<% end %>
</div>
</div>
これに伴い元々のversions/showをchanges/showへ移動しました。
表示はできたので、次は以前のバージョンに戻すことができるようにします。
PaperTrailにはreifyというメソッドが用意されているので、こちらを使って以前のバージョンに戻す処理を実装します。
# app/controllers/documents/versions_controller.rb
def update
@document = Document.find(params[:document_id])
@version = @document.versions.find(params[:id])
if @version.next.present?
@document = @version.next.reify
@document.save!
end
redirect_to document_path(@document)
end
reifyメソッドは現在参照しているバージョンの元々の状態に変更するため、参照しているバージョン自体をreifyしてしまうと、現在見ている内容のさらに前のバージョンに戻ってしまいます。
そのため現在参照しているバージョンの次のバージョンでreifyしています。
あとはルーティング、ボタンなどを用意してあげれば完成です。
寄り道も含めて簡単なドキュメント管理ツールを作成する方法を紹介してきましたが、いかがでしたでしょうか?
あくまで初歩的な実装ですが、ライブラリを利用することで自分だけのシンプルなツールを作成することができます。
ぜひ皆さんも自分だけのツールを作ってみてください!
次回は、せっかくなのでコンテンツにファイルを添付できるようにしてみたいと思います。
引き続きお楽しみに!
ここまでのコードは以下のリポジトリで確認できます。