1 Action Textとは?
Action Textは、リッチテキストコンテンツと編集をRailsにもたらします。それには、フォーマットからリンク、引用、リスト、埋め込み画像やギャラリーまで、すべてを処理するTrixエディタが含まれています。Trixエディタによって生成されるリッチテキストコンテンツは、既存のActive Recordモデルと関連付けられた独自のRichTextモデルに保存されます。埋め込み画像(またはその他の添付ファイル)は、Active Storageを使用して自動的に保存され、含まれるRichTextモデルと関連付けられます。
2 Trixと他のリッチテキストエディタの比較
ほとんどのWYSIWYGエディタは、HTMLのcontenteditable
とexecCommand
のAPIをラップしたもので、これはMicrosoftがInternet Explorer 5.5でウェブページのライブ編集をサポートするために設計したものであり、後に他のブラウザによって逆にエンジニアリングされ、コピーされました。
これらのAPIは完全に指定されたり文書化されたりしなかったため、WYSIWYG HTMLエディタは非常に広範なスコープを持っており、各ブラウザの実装には独自のバグやクセがあります。そのため、JavaScript開発者はこれらの不一致を解決する必要があります。
Trixは、contenteditableをI/Oデバイスとして扱うことで、これらの不一致を回避しています。入力がエディタに届くと、Trixはその入力を内部ドキュメントモデル上の編集操作に変換し、そのドキュメントをエディタに再レンダリングします。これにより、Trixは各キーストロークの後に何が起こるかを完全に制御し、execCommandを使用する必要がなくなります。
3 インストール
bin/rails action_text:install
を実行して、Yarnパッケージを追加し、必要なマイグレーションをコピーします。また、埋め込み画像やその他の添付ファイルにActive Storageを設定する必要があります。Active Storageの概要ガイドを参照してください。
注意:Action Textは、action_text_rich_texts
テーブルとの多態関連を使用しているため、リッチテキスト属性を持つすべてのモデルで共有できます。Action Textコンテンツを使用するモデルが識別子としてUUID値を使用している場合、Action Text属性を使用するすべてのモデルも一意の識別子としてUUID値を使用する必要があります。Action Textの生成されたマイグレーションも、:record
references
行に対してtype: :uuid
を指定するように更新する必要があります。
インストールが完了したら、Railsアプリには以下の変更が加えられます。
JavaScriptのエントリーポイントで
trix
と@rails/actiontext
の両方を要求する必要があります。// application.js import "trix" import "@rails/actiontext"
trix
のスタイルシートは、application.css
ファイルに含まれるAction Textのスタイルと一緒に含まれます。
4 リッチテキストコンテンツの作成
既存のモデルにリッチテキストフィールドを追加します。
# 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パッケージがインストールされていない限り、正しく表示されない場合があります。インストール方法については、インストールドキュメントを参照してください。
リッチテキストコンテンツを受け入れるために必要なのは、参照される属性を許可するだけです。
class MessagesController < ApplicationController
def create
message = Message.create! params.require(:message).permit(:title, :content)
redirect_to message
end
end
5 リッチテキストコンテンツのレンダリング
デフォルトでは、Action Textはリッチテキストコンテンツを.trix-content
クラスの要素内にレンダリングします。
<%# app/views/layouts/action_text/contents/_content.html.erb %>
<div class="trix-content">
<%= yield %>
</div>
このクラスを持つ要素と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
テンプレートを編集します。
5.1 添付ファイルのレンダリング
Active Storageを介してアップロードされた添付ファイルに加えて、Action Textは署名付きGlobalIDで解決できるものを埋め込むことができます。
Action Textは埋め込まれた<action-text-attachment>
要素を、そのsgid
属性をインスタンスに解決することでレンダリングします。解決されたインスタンスは、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
インスタンスの署名付きGlobalIDを参照する<action-text-attachment>
要素を埋め込むリッチテキストのコンテンツを考えてみましょう:
<p>Hello, <action-text-attachment sgid="BAh7CEkiCG…"></action-text-attachment>.</p>
Action Textは"BAh7CEkiCG…"という文字列を使用して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>
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>削除されたユーザー</span>
Action Textの<action-text-attachment>
要素のレンダリングと統合するためには、クラスは次のようにする必要があります:
ActionText::Attachable
モジュールを含めるGlobalID::Identification
concernを介して利用可能な#to_sgid(**options)
を実装する- (オプション)
#to_attachable_partial_path
を宣言する - (オプション)欠落したレコードを処理するためのクラスレベルの
#to_missing_attachable_partial_path
メソッドを宣言する
デフォルトでは、すべてのActiveRecord::Base
の子孫はGlobalID::Identification
concernをミックスインしており、したがってActionText::Attachable
と互換性があります。
6 N+1クエリを回避する
リッチテキストのフィールドがcontent
という名前の場合、依存するActionText::RichText
モデルを事前にロードしたい場合は、次のような名前付きスコープを使用できます:
Message.all.with_rich_text_content # 添付ファイルなしで本文を事前にロードします。
Message.all.with_rich_text_content_and_embeds # 本文と添付ファイルの両方を事前にロードします。
7 API / バックエンド開発
バックエンドAPI(例:JSONを使用)は、
ActiveStorage::Blob
を作成し、そのattachable_sgid
を返す別のエンドポイントが必要です:{ "attachable_sgid": "BAh7CEkiCG…" }
その
attachable_sgid
を取得し、フロントエンドに対して<action-text-attachment>
タグを使用してリッチテキストのコンテンツに挿入するように依頼します:<action-text-attachment sgid="BAh7CEkiCG…"></action-text-attachment>
これはBasecampに基づいていますので、まだお探しの情報が見つからない場合は、このBasecampドキュメントをご確認ください。
フィードバック
このガイドの品質向上にご協力ください。
タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。
不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。
修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください。
そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。