前提
rails標準のわりに使っている人の少ないturbolinksですが、僕は便利に使っています。turbolinksはご存知の通り、リンクを全部ajaxリクエストに置き換えてページ遷移を早くするライブラリです。
turbolinksが実現している「リクエストは全部ajaxにして、フルのページ遷移を避けたほうが速い」というロジックはformでも同じことが言えます。
Railsは5.1からform_with
というviewヘルパーが増えました。これは既存のform_tag
とform_for
を統合するヘルパーという位置づけですが、それ以外に大きな違いとしてデフォルトでdata-remote="true"
がformタグに付与される、というのがあります。この振る舞いはformもturbolinksみたいにajaxにしようぜ!というDHHの思想の現れなのだろう、と推測します。実際、form_withのPRでDHHがそんなようなことをコメントしていますね。
Make remote: true the default. Full-page changes after submissions are rough. When using Turbolinks, a normal redirect will generate a Turbolinks.visit() call, and otherwise there's SJR. (We could consider having config.action_view.forms_remote_by_default that you could set to false, for people going old school).
turbolinksはajaxを利用したform submitの一部に対応しています。具体的にはturbolinks gemはredirect_to
の挙動を差し替えており、form submitによるajaxリクエストをしたときのリダイレクト処理を非ajax時と同じ*1になるようにしています。書き換えたredirect_to
メソッドは、もしget以外のajaxリクエストから呼び出された場合、302を返さずに、クライアントサイドでTurbolinks.visit()
という画面遷移用のjs関数を実行するためのレスポンスを返します。この結果、ユーザとしては単にformをsubmitしてからredirect_toしたのと同じような画面遷移になります。
先程「turbolinksはajaxを利用したPOSTリクエストの一部に対応しています」と書きました。つまり対応していない部分があるということです。DHHが書いたコメントにもありますが、バリデーションエラーになった際の対応は、SJR(Server-generated JavaScript Responses)などを利用して各自でエラーメッセージを表示する処理を書かなければなりません。このあたりもうちょっとうまくできるとturbolinksもう少し普及するんじゃないのかな、という気がします*2。
最初はSJR部分を普通に書いていたのですが、統一的なインタフェースがあったほうが良さそうだな、と思ったのでgemにしてみました。
willnet/ajax_error_renderer: a validation error renderer for ajax request
ajax_error_rendererとは
render_ajax_error
という、ajaxでエラーメッセージを表示するメソッドを提供する小さなgemです。次のようにAjaxErrorRenderer
をincludeすると使えるようになります。
class ApplicationController < ActionController::Base include AjaxErrorRenderer end
ajaxでリクエストが来てエラーメッセージを表示する場面でrender_ajax_error
メソッドを使います
class UsersController < ApplicationController def create @user = User.new(params.require(:user).permit(:name)) if @user.save redirect_to users_path, notice: 'You created a user successfully!' else render_ajax_error model: @user end end end
すると#error
なDOMに動的にエラーメッセージが表示されるようになります
<%= form_with(model: @user) do |form| %> <div id="error"> <%# ここにエラーメッセージが表示される %> </div> <div class="field"> <%= form.label :name %> <%= form.text_field :name %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>
基本的な使い方は以上です。簡単ですね。どうぞご利用ください。