※ 「あなたがRails触る人なら見ておきたい「体系的な」豆知識」からの派生記事です。
Railsでフォームに入力した文章をリロード無しで保存、描画することで最も簡単なAjaxの流れの説明を試みたいと思います。
Ajaxとは
「Ajaxとは」と検索すると大量に説明文が出てきますがよく「非同期通信の総称」とかいう記述を目にします。
難しい話はよくわからないので「何かフォームからデータを送信した時にページをリロードせずにデータの保存・描画を行う」ことだとしましょう。以下のような感じです。
いちいちリロードしないとは素晴らしいですね!
これを応用すると「いいねボタン」なども簡単につくれます。
Ajax通信の必要条件
- formにremote属性がセットされていること
- 対応するアクションが存在すること
- 対応するJSファイルが存在すること
実はこれくらいです。
ファイルを作り、記述をちょちょいっと変えるだけでAjaxは導入できてしまいます。
Ajax通信のイメージ
順を追って見て行きましょう。
- 非同期通信の発生
- 上記のようにフォームにAjaxを導入したときは、submitボタンを押した時に「 非同期通信を行いなさい 」という指令がControllerに飛びます。
- JSの応答
- 非同期通信を行うよう指令を受けたControllerは指定のアクションを実行し、その後テンプレートファイルを読み込みにかかります。
- 通常ここではフォーマットを指定しない限りHTMLファイルが読み込まれますが、「非同期通信を行いなさい」と指定されたControllerはHTMLファイルを読み込まず アクション名と対応したJSファイル を読み込みにかかります。
-
update
アクションを実行したのであれば対応するJSファイルはupdate.js.erb
です。
- スクリプトの実行
- JSファイルが読み込まれると中に記述してあるスクリプトを実行し、一連の処理を終了します。
- このスクリプトに「 ビューの中のこの部分をこのように変更しなさい 」という指示を織り込むことで、ページリロードせずともページ内の一部表示が再描画されるのです。
実際に書いてみる
今回題材にするのは、あるプロトタイプの投稿に対する「コメント機能のAjax化」です。
上記で示した順序に沿って実装してみましょう。
-
Ajaxする前の段階を確認
【 View 】prototypes/show.html.haml%div = render @prototype.comments %div = form_for @new_comment do |f| %h4 Write a comment = f.text_area :text = f.submit :comment, class: "btn btn-primary"
prototypes/_comment.html.haml%div %div = image_tag comment.avatar_thumbnail %div %h4 = comment.user.name %p = comment.text
【 Controller 】
```comments_controller.rb
def create
Comment.create(comment_params)
@prototype = Prototype.find(params[:id])
redirect_to prototype_path(@prototype)
end
```
- コメントを書いて投稿ボタンを押すと、「ページがリロードされて書いたコメントが表示される」という何の変哲もないフォームです。
-
投稿ボタンを押した時に非同期通信が走るようにする
sample.html.haml#comments = render partial: 'prototypes/comment', collection: @prototype.comments %div = form_for @new_comment, remote: true do |f| %h4 Write a comment = f.text_area :text, id: "comment_field" = f.submit :comment, class: "btn btn-primary"
prototypes/_comment.html.haml-# 変更なし
- まずは送信ボタンを押した際に「非同期通信を行いなさい」という指令が出るようにしたいのですが、これは
form_for
に対してremote: true
を設定して完了です。 - 後々JSによる操作を行いやすくするために、「コメントを表示する部分(
#comments
)」と「コメントを入力するフィールド(#comment_field
)」にそれぞれ固有のidを付与しています。
-
非同期通信が走った後に投稿を保存しJSのテンプレートファイルを呼び出す
comments_controller.rbdef create Comment.create(comment_params) @prototype = Prototype.find(params[:id]) end
- redirect処理を消去しただけです。これでアクション名と対応したJSテンプレートファイルを読み込みにいってくれます。
-
スクリプトを実行してコメント部分のみ再描画する
comments/create.js.erb$('#comment_field').val(''); $('#comments').html( '<%= j(render partial: 'prototypes/comment', collection: @prototype.comments) %>' );
- JSテンプレートファイルは
js.erb
形式で他のビューファイルと同ディレクトリに作成し、読み込まれるとファイル中のスクリプトを実行してくれます。 - 今回の場合は、投稿ボタンを押したタイミングで以下の動作を行っています。
-
コメントを入力するフィールドの文字を消去し
$('#comment_field').val('');
-
コメントを表示する部分のHTMLを再描画する
$('#comments').html('<%= j(render partial: 'prototypes/comment', collection: @prototype.comments) %>');
-
-
jメソッド
はビューヘルパーであるescape_javascriptメソッド
のエイリアスです。クォーテーションや改行をエスケープしてくれるため、慣習的に付けておきます。 - 今回使用しているように、JSテンプレート内では外部の部分テンプレートも問題なく呼び出すことができます。
動作を確認してみる
ここまでで大方仕様は作りこめたので、動かしてみましょう+(0゚・∀・) + ワクテカ +
うごいたぁぁぁぁ!!
カウンター部分は今回解説に含めていないので、どうすればできそうか考えてみてください。
ちなみに応用するといいねボタンもつくれます。
こんな感じですが、まずは習うより慣れろです!
コピペでも構わないので、まずは自分の今書いているコードに導入してみてください。