Rails + Trix + Stimulusで作るドキュメント管理ツール — 画像添付編
前回の投稿から間が空いてしまいましたが、本日はコンテンツの中に画像を添付できるようにしたいと思います。
- Rails + Trix + Stimulusで作るドキュメント管理ツール — 導入編 — Ruffnote — Medium
- Rails + Trix + Stimulusで作るドキュメント管理ツール — 編集履歴編 — Ruffnote — Medium
- Rails + Trix + Stimulusで作るドキュメント管理ツール — Trix導入編 — Ruffnote — Medium
- Rails + Trix + Stimulusで作るドキュメント管理ツール — 差分表示編 — Ruffnote — Medium
画像はダイレクトアップロードして、アップロードした結果をコンテンツの中に埋め込む形になります。
ファイルアップロードには ActiveStorage を使用したいと思います。
まずは ActiveStorage のインストールコマンドを実行し、データベースのマイグレーションをします。
$ bin/rails active_storage:install
$ bin/rails db:migrate
タイトルに Stimulus と書いておきながら、結局使っていなかったので、今回は折角なので Stimulus も使ってみたいと思います。
$ bin/rails webpacker:install:stimulus
今回は Stimulus の細かな扱い方は説明しません。ドキュメントがしっかりしているので、そちらを読めば問題ないかと思います。
それではさっそく画像アップロードの実装に入りたいと思います。
Trix エディタを trix_controller.js で扱えるようにします。
Trix エディタを以下のように controller でラップしてあげます。
<div data-controller="trix">
<%= form.hidden_field :content %>
<trix-editor input="document_content" class="trix-content"></trix-editor>
</div>
それから trix_controller.js を用意します。
# app/javascript/controllers/trix_controller.js
import { Controller, } from 'stimulus';export default class extends Controller {
initialize() {
console.log('trix_controller.js');
}
}
以下のように console.log の結果が出力されれば準備OKです。
Trixではファイルがドラッグまたはペーストされると trix-attachment-add イベントが呼び出されます。
Stimulus でイベントとアクションを紐づけてみます。
# app/views/documents/_form.html.erb
<trix-editor input="document_content" class="trix-content" data-action="trix-attachment-add->trix#attach"></trix-editor># app/javascript/controllers/trix_controller.js
export default class extends Controller {
attach(e) {
console.log('attached');
}
}
しっかりとイベントをキャッチできていることが確認できました。
それではここからダイレクトアップロードの実装を追加します。
ActionText の実装を利用させてもらうことにします。
こちらを利用するために yarn で ActiveStorage をインストールしておきます。
$ yarn add activestorage
そしてHTMLに必要なdata属性を定義して、この AttachmentUpload に必要なデータを渡してあげればダイレクトアップロードができるようになります。
# app/views/documents/_form.html.erb
<div data-controller="trix" data-direct-upload-url="<%= rails_direct_uploads_url %>" data-blob-url-template="<%= rails_service_blob_url(':signed_id', ':filename') %>"># app/javascript/controllers/trix_controller.js
attach(e) {
const attachmentUpload = new AttachmentUpload(e.attachment, this.element);
attachmentUpload.start();
}
これだと添付した画像とモデルとの関連がわからなくなるので、コンテンツを parse して画像ファイルの部分を抜き出して、モデルと関連付ける必要があります。
まずは Document モデルに画像ファイルを関連付けできるように設定を追加します。
# app/models/document.rb
has_many_attached :embeds
ダイレクトアップロードした後は以下のような形で添付したファイルが1つの塊として要素になっています。
なので、こちらの内容を parse して該当のモデルに関連付けしてあげます。
# app/models/document.rb
before_save :set_embedsprivatedef set_embeds
return if content.blank? nokogiri_html = Nokogiri::HTML.parse(content)
sgids = nokogiri_html.css('figure').map do |figure|
trix_attachment = JSON.parse(figure['data-trix-attachment'])
trix_attachment['sgid']
end
blobs = sgids.map { |sgid| ActiveStorage::Blob.find_signed(sgid) } self.embeds = blobs - embeds.map(&:blob)
end
すごく簡単な実装なので、色々と問題はあると思いますが、これで添付したファイルとモデルの関連付けができるようになりました。
ざっくりとした説明となりましたが、これで ActiveStorage と Trix と Stimulus を使った画像添付処理が実装できました。
React や Vue が巷では流行っていますが、 Stimulus もなかなかに便利なので、機会があればぜひ触ってみてはいかがでしょうか。(毛色は違いますが。
ここまでのコードは以下のリポジトリで確認できます。