Rails + Trix + Stimulusで作るドキュメント管理ツール — 画像添付編

Kota Miyake
Ruffnote
Published in
7 min readDec 18, 2018

前回の投稿から間が空いてしまいましたが、本日はコンテンツの中に画像を添付できるようにしたいと思います。

画像はダイレクトアップロードして、アップロードした結果をコンテンツの中に埋め込む形になります。

ファイルアップロードには 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_embeds
privatedef 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 もなかなかに便利なので、機会があればぜひ触ってみてはいかがでしょうか。(毛色は違いますが。

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

--

--