Trix および Turbo Frame を使用して Rails で動的テーブル エディタを作成する
この投稿では、Rails アプリケーションに基本的な ActionText テーブル エディタを実装します。次の方法を学習します。
- ActionText と Trix は添付ファイルを処理します
- 独自の
Attachableを実装するには と入力し、これを活用して基本的なテーブル エディタを構築します - ターボ フレームを使用してテーブルを編集できます
- ターボは役立つと同時に邪魔にもなります
この記事は、2020 年の優れたブログ投稿「Stimulus.js を使用して ActionText にテーブルを追加する」からインスピレーションを得ています。ただし、これは Turbo の出現前に書かれたものであり、これにより問題がかなり簡素化されることが期待できます。
さあ、始めましょう!
Rails 101 の ActionText 添付ファイル
メモ :このデモンストレーションは、Trix および Turbo Frames をある程度理解していることを前提としています。 Hotwire と Turbo Frames の基本を学ぶには、「Ruby on Rails アプリで Hotwire を使ってみる」 の投稿が役立つかもしれません。
この GitHub リポジトリのコード デモに従うことができます。
ActionText のドキュメントで説明されているように:
Action Text は、Rails にリッチ テキスト コンテンツと編集をもたらします。これには、書式設定からリンク、引用符、リスト、埋め込み画像やギャラリーに至るまで、あらゆるものを処理する Trix エディターが含まれています。
大まかに言うと、添付ファイルは ActionText のドキュメント モデルの一部です。これらは、署名付きグローバル ID (SGID) によって解決可能なリソースのカスタム テンプレートをレンダリングします。つまり、ActionText は特定の SGID への参照を <action-text-attachment> として保存します。 要素:
ActionText がそのような要素に遭遇すると、to_attachable_partial_path が呼び出されます。 それぞれのリソースのメソッド。デフォルトでは、このメソッドは to_partial_path に委譲します。 .
プレビューとして、Table は次のようになります。 ActionText での の表現は、HTML にレンダリングされたときに次のようになります。
ActionText Attachment API に準拠するには、クラスは次の 2 つのことだけを実行する必要があります。
<オル>to_sgid を実装します。 GlobalID::Identification を含めることにより 。デフォルトでは、すべて ActiveRecord::Base 子孫はすでにこれを行っています。ActionText::Attachable を含めます モジュール。
ActionText::Attachable モジュールは、attachable_sgid を介して任意のモデルを SGID に変換したり、SGID から SGID に変換したりする正規の方法を提供します。 と from_attachable_sgid 方法。これは後で使用します。
また、コンテンツ タイプだけでなく、ファイル サイズや名前などの添付ファイルのメタデータに対する便利なアクセサーも提供します。
最後に、エディターおよびリッチ テキスト ビューで添付ファイルをレンダリングするために使用されるパーシャルのデフォルトの場所を提供します。
テーブル モデルの追加
ActionText の Attachment API を利用して、テーブル ソリューションを実装します。このためには、テーブルのデータをキャプチャするカスタム モデルを作成し、Attachable を含める必要があります。 。単純な JSON(B) 列を使用して、テーブル データの 2 次元配列を保持します。
探索を開始するには、ActionText を有効にして新しい Rails アプリを作成しましょう。
今日はクリエイティブな気分ではないので、Article を足場にしましょう タイトルとリッチ テキスト コンテンツを含むモデル:
気を付けてください、ここに驚くべき落とし穴があります!上記のインストール コマンドにより、CreateActionTextTables が作成されました。 移行するため、名前を CreateActionTextTablesTable に変更する必要があります。 。さらに、null: false, default: [["", ""], ["", ""]] を使用してデフォルトで 2x2 テーブルに設定します。 .
Rails ActionText モデルにテーブルを追加する
実際にリッチ テキストにテーブルを追加する作業を続行する前に、Trix のツールバーにパッチを適用する必要があります。
ここでは、Trix の toolbarElement にボタンを手動で追加します。 。これを trix-table に接続します スティミュラス コントローラー (まだ構築していません) はドキュメントにテーブルを挿入します。このボタンに CSS のコンテンツとして優れた SVG を与え、その際にテーブル スタイルをいくつか設定しましょう。
ご覧のとおり、「file-tools」グループに正常に追加されました。

ここで、Turbo を使用したテーブルの追加と操作に戻りましょう。このためには、まず create を持つコントローラーが必要です。 アクション:
このアクションは、冒頭で引用した「On Rails」ブログ投稿から多かれ少なかれ借用できます。クライアント側で添付ファイルを挿入するために必要な JSON を構築します。これには SGID と content が含まれます。 editor からレンダリング 後で説明するように、部分的です。
関連するリソース豊富なテーブル ルートを追加します。 設定に合わせて:
ここで、いよいよ奥深くに突入します。テーブル モデルを構築する必要があります。まず、ActionText::Attachable を含めてみましょう。 関連する部分パスを定義します。
テーブルのコンテンツをどのように保存するかをまだ定義していないことに注意してください。データベース内で JSON(B) 列として宣言したため、任意の形式を自由に選択できます。引用したブログ投稿から少し逸れますが、2 次元配列を使ってみましょう。したがって、content に対してネストされたループを実行するだけで済みます。 このように:
上記の部分は、ActionView によってリクエストされるたびにレンダリングされます。 たとえば。次に、editor も考案する必要があります。 Trix でインラインで使用される部分:
唯一の違いは、おそらくお気づきかと思いますが、SGID を DOM ID として使用して、Turbo Frame でラップしていることです。さらに、区切りブロックに行と列のインデックスを提供し、内部 DIV を contenteditable にしてインライン編集の準備をします。 — それについては後で説明します。
次に、ツールバーのテーブル ボタンを、先ほど作成したサーバー側コントローラー アクションに接続します。これを行うには、まず Rails の request.js ライブラリをプロジェクトに組み込む必要があります。このライブラリは、post の管理に役立ちます。 適切な CSRF トークンなどを含む、クライアントからのリクエスト:
新しい Trix テーブル スティミュラス コントローラーを構築する
すべての設定が完了したので、 新しいトリクステーブルを作成しましょう。 刺激コントローラー。その中で、attachTable を実装します。 ツールバー ボタンによって参照されるアクション:
テーブルの create に POST されます。 ルート、JSON 応答をTrix 添付ファイルとして挿入します。 。これも OnRails ブログ投稿から借用し、非推奨のrails-ujs を置き換えます。 新しいrequest.jsを呼び出します。 ライブラリ。
次に、このコントローラをフォームのマークアップに追加して、実際にアプリでこのコントローラを使用する必要があります。
Stimulus.js の利点は、form に 2 つのデータ属性を追加するだけであることです。 要素は望ましい結果を達成します。ボタンを 1 回クリックするだけで、記事のコンテンツに表を追加できるようになりました。

ターボ フレームを介したテーブルの操作
テーブル添付ファイルを作成できるようになったので、コンテンツの操作に焦点を移しましょう。結局のところ、ターボフレームはほぼです。 ここでは自然にフィットします。
テーブルの行と列の追加と削除
テーブルの行と列を追加および削除するには、操作ごとに 1 つずつ、計 4 つのボタンで構成されるミニツールバーを作成します。 button_to を使用します。 ヘルパーを作成し、URL を update に設定します。 それぞれのテーブルのルート。トリガーしたいそれぞれのオペレーションを追加パラメータとして追加しましょう:
次に、それぞれのコントローラー アクションを TablesController に追加する必要もあります。 。 update を確認してください。 action はそれらのアクションをモデルに委任します。
テーブルの構造への変更が保存された後、テーブルの編集ビューにリダイレクトされます。同じ editor をレンダリングします。 部分的ですが、同じターボ フレームを参照するという副作用があります。したがって、Turbo は一致するフレームを検出し、一方を他方と置き換えることができます。
次に、不足しているコマンドを Table に実装する必要があります。 モデル。
特に、2 次元配列の単純なデータ構造により、add/remove<sub>column</sub>/row メソッドは、列と行の数を変更するための単なるプロキシです。これを配置したら、ボタンをクリックしてテーブルの構造を変更できます。

表のセルの内容を編集する
列と行の数を変更するだけでなく、セルの内容も編集したいと考えています。これを達成するために、再び引用されたブログ投稿に重点を置き、Stimulus テーブル エディター コントローラーを作成します。
updateCell このメソッドはセルが編集されるたびに PATCH リクエストを発行し、行と列のインデックスをパラメータとして渡します。あとは、DOM に接続するだけです。
サーバー側の TablesController もちろん、この操作を処理する方法が必要になります。幸いなことに、これは、条件に別のブランチを追加することで、簡略化された概念実証で簡単に実行できます。また、update が アクションは、ここで単に空のオブジェクトを返すだけであっても、JSON タイプのリクエストを処理できるようになりました。
実稼働アプリでは、操作をサニタイズするために if/elsif/else とは異なる戦略を選択することをお勧めします。 状態。この場合、私はおそらく調停者か代理人に頼ることになるでしょう。
Ruby における Trix の制限
ここまでは、この説明は完全に理にかなっていると思いますが、重要な詳細を省略しました。基礎となるデータベース モデルは問題なく永続化されていますが、それを Trix の内部シャドウ表現と同期していません。そのため、テーブルからフォーカスを外したときに、テーブルが以前に保存された表現にスナップバックします。

ここでページを更新すると、Trix のドキュメントが新しく初期化されたため、追加されたコンテンツが表示されます。
私はこの問題を、選択が変更されたときに Trix が内部ドキュメントを同期する場所に原因があることを突き止めました。ここではシャドウ要素から展開するだけです。
turbo:submit にフックしてみました
これに対処する最も Turbo らしい方法は、フォーム全体を積極的にロードされる Turbo Frame でラップし、Trix のコンテンツが変更されるたびにリロードするように指示することだと思います。
次のようなものでうまくいくはずです:
src からロードする Turbo Frame でフォームを囲む場合 :
ただし、このアプローチは、すでに永続化されている基本レコードでのみ機能します。
トリックスに対する最後の警告
私たちが構築した概念実証では、サーバーでレンダリングされた HTML を使用して、テーブルを JSON にシリアル化し、JavaScript イベントをリッスンするという複雑さを排除しています。これは、任意の ActionText インストールに移植可能であり、gem に簡単に抽出できます。
ただし、いくつかの欠点があります。最も明らかな欠点は、Trix のドキュメント モデルとの再同期が必要なことです。提案された回避策が実行可能な状況もあれば、実行できない状況もあるかもしれません。 Trix が Turbo 互換インターフェイスを取得するまで、これを回避する方法はありません。
2 つ目の問題は、Trix の undo を使用していないことです。 機能 (ただし、これはどの Trix アタッチメントにも当てはまります)。同様に、内部 API を微調整するのではなく、アップストリームの変更を待つことが賢明です。
まとめ
この投稿では、ActionText 添付ファイルの基本を簡単に説明することから始めました。次に、Turbo Frames を使用して微調整する前に、ActionText モデルにテーブルを追加しました。最後に、Trix の使用に関するいくつかの制限について触れました。
CoffeeScript からプレーンな最新の JavaScript への変換を特徴とする Trix v2 が進行中であることを考えると、今がその Turbo 互換性に取り組む良い時期と言えるでしょう。現時点では、そのようなラッパーがどのようなものであるかは私の能力を超えていますが、チャンスの窓であることは確かです。
コーディングを楽しんでください!
追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。
-
Rubyの実用的なリンクリスト
これは、「Rubyの実用的なコンピュータサイエンス」シリーズの3番目のエントリです。今日はリンクリストについてお話します。 では、リンクリストとは何ですか? 名前が示すように、リンクリストはデータをリスト形式で保存する方法です(ありがとう、キャプテンオブビシャス!)。 「リンクされた」部分は、データがノードに格納され、これらのノードが順番に相互にリンクされているという事実に由来します。 これはアレイとどう違うのですか? リンクリストと配列 リンクリストには、配列とは異なるパフォーマンス特性があります。これが、どちらかを選択する理由の1つです。 これは、リンクリストが配列よりも
-
RubyでのAWSLambda関数の記述
AWS Lambdaを使用すると、オーバーヘッドを最小限に抑えながらスケーラブルな関数をセットアップできます。 Ruby on Railsアプリ全体を作成、ホスティング、保守する代わりに、Lambda関数を使用して個々のイベントに個別に応答できます。この記事では、AWSの初心者から、独自のLambda関数でRubyを作成する方法について説明します。 Lambdaを使用すると、サーバーを管理しなくても、イベントに応答してコードを実行できます。このイベント駆動型アーキテクチャにより、コードの支払いは、アイドリング中ではなく、機能している間だけになります。 Lambdaは、S3バケット内のファイル