本ガイドでは、リッチテキストコンテンツの扱いを始めるのに必要なものをすべて提供します。
このガイドの内容:
Action Textを使って、Railsにリッチテキストコンテンツと編集機能を導入できます。Action Textに含まれているTrixエディタは、書式設定/リンク/引用/リスト/画像埋め込み/ギャラリーなどあらゆるものを扱えます。
Trixエディタが生成するリッチテキストコンテンツは独自のRichTextモデルに保存され、このモデルはアプリケーションの既存のあらゆるActive Recordモデルと関連付けられます。
あらゆる埋め込み画像(およびその他の添付ファイル)は自動的にActive Storageに保存され、include
されたRichTextモデルに関連付けられます。
ほとんどのWYSIWYGエディタは、HTMLのcontenteditable
やexecCommand
APIのラッパーです。これはマイクロソフトがInternet Explorer 5.5のライブエディット機能をサポートするために設計したもので、最終的にリバースエンジニアリングされて他のブラウザに普及しました。
これらのAPIの仕様やドキュメントは永遠に未完成のままであり、かつWYSIWYG HTMLエディタが扱う範囲が広大なため、ブラウザの実装ごとに独自のバグやおかしな動作が発生しています。ブラウザ間の動作のぶれの解決はJavaScript開発者たちに任せきりの状態です。
Trixではcontenteditable
をI/Oデバイスとして扱うことで、こうしたブラウザ間の動作のぶれを回避しました。エディタに独自の方法で入力されると、Trixはその入力を内部のドキュメントモデル上での編集操作に変換してから、ドキュメントをエディタ上で再レンダリングします。これにより、Trixはあらゆるキーストロークで発生するものを完全に制御し、execCommand
を使う必要性をすべて回避しています。
rails action_text:install
を実行すると、Yarnパッケージが追加され、必要なマイグレーションがコピーされます。また、埋め込み画像や他の添付ファイルを扱うためにActive Storageのセットアップも必要です。詳しくはActive Storageの概要ガイドを参照してください。
Action Textでは、action_text_rich_texts
テーブルとのポリモーフィックなリレーションシップを利用して、リッチテキスト属性を持つあらゆるモデルで共有できるようになっています。Action Textコンテンツを持つモデルがUUID値をidに使っている場合、Action Text属性を使うすべてのモデルで固有のidにUUID値を使う必要が生じます。また、Action Text用に生成されるマイグレーションでは、:record
のreferences
行にtype: :uuid
を指定する形に更新する必要もあります。
インストールが完了すると、Railsアプリは以下のように変更されるはずです。
JavaScriptのエントリポイントにtrix
と@rails/actiontext
の両方を含める必要があります。
// application.js import "trix" import "@rails/actiontext"
trix
スタイルシートは、自分のapplication.css
ファイルでAction Textスタイルとともにインクルードされます。
既存のモデルにリッチテキストのフィールドを追加するには次のようにします。
# app/models/message.rb class Message < ApplicationRecord has_rich_text :content end
または、新しいモデルを生成するときに以下のようにリッチテキストフィールドを追加します。
$ bin/rails generate model Message content:rich_text
自分のmessages
テーブルにcontent
フィールドを追加する必要はありません。
次に、フォーム内でモデルのこのフィールドをrich_text_area
を用いて参照します。
<%# app/views/messages/_form.html.erb %> <%= form_with model: message do |form| %> <div class="field"> <%= form.label :content %> <%= form.rich_text_area :content %> </div> <% end %>
最後に、サニタイズ済みのリッチテキストをページ上に表示します。
<%= @message.content %>
content
フィールドに添付されたリソースがある場合、自分のコンピュータにlibvips/libvips42パッケージがローカルにインストールされていないと正しく表示されない可能性があります。インストール方法については、libvipsのドキュメントを参照してください。
リッチテキストコンテンツをコントローラで受け取れるようにするには、参照される属性を許可するだけで済みます。
class MessagesController < ApplicationController def create message = Message.create! params.require(:message).permit(:title, :content) redirect_to message end end
デフォルトでは、Action Textは.trix-content
CSSクラスを宣言した要素内でリッチテキストコンテンツをレンダリングします。
<%# app/views/layouts/action_text/contents/_content.html.erb %> <div class="trix-content"> <%= yield %> </div>
この.trix-content
クラスを持つ要素のスタイルは、Action Textエディタと同様に、trix
スタイルシートによって設定されます。
独自のスタイルを提供するには、インストーラーが作成するapp/assets/stylesheets/actiontext.css
スタイルシートから= require trix
行を削除してください。
リッチテキストの周りに表示されるHTMLをカスタマイズするには、インストーラが作成するapp/views/layouts/action_text/contents/_content.html.erb
レイアウトを編集してください。
埋め込み画像やその他の添付ファイル(いわゆるblob)に対してレンダリングされるHTMLをカスタマイズするには、インストーラが作成するapp/views/active_storage/blobs/_blob.html.erb
テンプレートを編集してください。
Action Textでは、Active Storage経由でアップロードした添付ファイルを埋め込むことも、署名済みグローバルIDで解決可能な任意のデータを埋め込むこともできます。
Action Textは、sgid
属性を解決してインスタンス化することで埋め込み<action-text-attachment>
をレンダリングします。解決が成功すると、そのインスタンスがrender
に渡されます。
生成されるHTMLは、<action-text-attachment>
要素の子孫として埋め込まれます。
たとえばUser
モデルを例に考えてみましょう。
# app/models/user.rb class User < ApplicationRecord has_one_attached :avatar end user = User.find(1) user.to_global_id.to_s #=> gid://MyRailsApp/User/1 user.to_signed_global_id.to_s #=> BAh7CEkiCG…
次に、 User
インスタンスにある署名済みグローバルIDを参照する<action-text-attachment>
要素が埋め込まれたリッチテキストを考えてみましょう。
<p>Hello, <action-text-attachment sgid="BAh7CEkiCG…"></action-text-attachment>.</p>
Action Textは、この"BAh7CEkiCG…"というStringを用いてUser
インスタンスを解決します。
次に、アプリケーションのusers/user
パーシャルを考えてみましょう。
<%# app/views/users/_user.html.erb %> <span><%= image_tag user.avatar %> <%= user.name %></span>
Action TextでレンダリングされるHTMLは以下のようになります。
<p>Hello, <action-text-attachment sgid="BAh7CEkiCG…"><span><img src="..."> Jane Doe</span></action-text-attachment>.</p>
別のパーシャルをレンダリングするには、以下のようにUser#to_attachable_partial_path
を定義します。
class User < ApplicationRecord def to_attachable_partial_path "users/attachable" end end
次にそのパーシャルを宣言します。User
インスタンスは、パーシャル内のuser
ローカル変数でアクセスできます。
<%# app/views/users/_attachable.html.erb %> <span><%= image_tag user.avatar %> <%= user.name %></span>
Action TextがUser
インスタンスを解決できない場合(レコードが削除されているなど)、デフォルトのフォールバックパーシャルがレンダリングされます。
Railsでは、添付ファイルが見つからない場合のグローバルパーシャルを用意しています。このパーシャルはアプリケーションのviews/action_text/attachables/missing_attachable
にインストールされます。これを変更することでレンダリングされるHTMLを変更できます。
添付ファイルがない見つからない場合にレンダリングするパーシャルを変更するには、以下のようにクラスレベルのto_missing_attachable_partial_path
メソッドを定義します。
class User < ApplicationRecord def self.to_missing_attachable_partial_path "users/missing_attachable" end end
次にそのパーシャルを宣言します。
<%# app/views/users/missing_attachable.html.erb %> <span>Deleted user</span>
Action Textの<action-text-attachment>
要素レンダリングと統合するには、クラスが以下の条件を満たさなければなりません。
ActionText::Attachable
モジュールをinclude
していること#to_sgid(**options)
を実装していること(GlobalID::Identification
concern)経由で利用可能)#to_attachable_partial_path
を宣言していること#to_missing_attachable_partial_path
を宣言していることデフォルトでは、ActiveRecord::Base
のすべての子孫はGlobalID::Identification
concernをミックスインするので、ActionText::Attachable
と互換性があります。
依存するActionText::RichText
をプリロードしたい場合は、以下のように名前付きスコープを利用できます(リッチテキストフィールド名がcontent
という前提)。
Message.all.with_rich_text_content # 添付ファイルなしで本文をプリロードする Message.all.with_rich_text_content_and_embeds # 本文と添付ファイルを両方プリロードする
たとえばJSONを使うバックエンドAPIで、ファイルアップロード用に別のエンドポイントが必要だとします。このエンドポイントはActiveStorage::Blob
を作成してそのattachable_sgid
を返します。
{ "attachable_sgid": "BAh7CEkiCG…" }
そのattachable_sgid
を受け取ったら、<action-text-attachment>
タグのあるリッチテキストコンテンツに挿入するようフロントエンド側に依頼します。
<action-text-attachment sgid="BAh7CEkiCG…"></action-text-attachment>
これはBasecampをベースにしているので、詳しい情報についてはBasecampのドキュメントを参照してください。
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。