何をしたか
Railsでアプリを作っています。タイトルの通りなのですが、remote: true
でajax
の投稿ができるフォームを作りました。
初回ではないのでスルスル作れたのですが、手順や考え方がしっかり身についていないので、自分のためのノートとしてメモします。
なお、実行環境は以下の通りです。
Rails 5.2.3
Ruby 2.6.0
参考記事
実装にあたっては、以下の記事を大変参考にさせていただきました。
【Rails】remote: trueでフォーム送信をAjax実装する方法とは?
今回の手順も↑こちらとそっくりになってしまったので、丁寧な解説をみたい方は上記の記事を見ていただいた方が良いかと思います。(こちらはあくまでも、私自身のためのメモですので。。。。)
実装方法
作ったもの
今回作ろうとしたのは、こんな感じの、投稿にぬるぬるとコメントを投稿できる仕組みです。DB構造的にはposts
テーブルに紐づくcomments
がある状況です。(画像は作成中のものなので、そのうち挿げ替えるかもしれません。)
remote: trueのフォームを作ってみる
まずは、通常通りコメントを投稿するフォームを作ってみました。なお、装飾のためのclassや、今回の実装に関係ない要素は省略しています。(以下、全てのコードで同じ)
= form_with model: [@post, @comment] do |f|
= f.text_field :text
= f.submit '投稿'
form_with
はデフォルトがremote: true
なので、local: true
もついていない、非常にシンプルなフォームになっています。
controller
def create
@comment = @post.comments.build(comment_params)
@comment.save!
end
controllerも非常にシンプルにしました。
なお、今回はremote: true
の挙動確認が主な目的なので、
1) redpond_to, formatでhtmlとjsの処理を分けること
2)@commentが保存できなかった時のエラーハンドリング
は実装していません。
2)ついては別記事にしたいなとも思うのですが、実際に実装するときには上記の2点も考慮しているというのは追記しておきます。
とにかくにも、上記のcontrollerによってjsフォーマットのcreate.js.erb
が呼び出されるようになります。
create.js.erb
ところで、**.js.erb
って、聞き慣れないファイル名ですよね。このファイルは何ができるかというと、(以下、先に紹介したこちらの記事からの引用です。)
- ファイル内に記述したJavaScriptのコードを実行する
- ERBタグを使用することができる
- インスタンス変数を使用することができる
上記のことができます。便利ですね
なので、上記に記した、create.js.erb
に例えば下記の様に書くと...。
$('.comments').append("<%= @comment.text %>");
それだけでこのようなビューを作ることができます。
まだ形は整っていないですが、ぬるぬると投稿が表示されていきますね
補足1:投稿をする先のビューについて
なお、順番が前後してしまいましたが...。今回投稿をする先のビューはこの様な構造になっています。
.comments
= render @comments
.comments
クラスの下に、@comments
の中身を展開して呼びだす構造になっていて、(←こちら、すごく端折った書き方ですので、「???」という方はこちらの記事をご覧ください)
先に書いたこのコードで、
$('.comments').append("<%= @comment.text %>");
.comments
内の@comment
群の末尾に、投稿した新しい@comment
が足されていきます。
補足2:実際に書いたコードについて
実は上記のコードだけでは、投稿後、フォームの中に投稿したコメントが残り続けます。そのため、実際には下記の様なコードを書いています。
= form_with model: [@post, @comment], class: 'js-comment-form' do |f| #追記
= f.text_field :text
= f.submit '投稿'
フォームにjs-comment-form
というクラスをつけ、
$('.comments').append("<%= @comment.text %>");
$('.js-comment-form')[0].reset();
テキストの追加後、.js-comment-form
の中身をリセット(空に)しています。
create.js.erbでのパーシャルの呼び出し
とにかくにも、これで非同期で投稿できる様になりましたので、あとはもう少し見た目をリッチにしていきたいと思います。
結論から言うと、書いたコードは下記の通りです。
$('.comments').append("<%= j(render 'comment', comment: @comment) %>");
まず、render 'comment'
の部分で、comments/_comment
のパーシャルを呼び出しています。
(先の補足1の箇所に戻りますが、今回、コメントを投稿する先のビューは下記の通りです。したがって_comment
というパーシャルが存在します。)
.comments
= render @comments
次に、j
メソッドでJavaScript
のコードをエスケープしています。この辺りは、この2記事を読んで理解を深めました。
パーシャルの中身は、詳しくは省略しますが、大体こんな感じです。こちらはhaml
やslim
などを使って書いてなんら問題ありません。
div
= アイコンの画像
= comment.user
div
= comment.text
div
= 削除アイコン
= 編集アイコン
完成!
ちょっと苦手なところだったのですが、一段落したところで記事を書くことで、実装に関する理解を深め、ついでにリファクタリングもできました
これから、エラーハンドリングや編集・削除の非同期での実装も頑張っていきたいです。