前提
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 %>
基本的な使い方は以上です。簡単ですね。どうぞご利用ください。