【Ruby】チュートリアルのform_forをform_withで書き換え (おまけ:capybaraでのテスト)
Ruby5.1前まではフォームを生成してくれるメソッドとして、form_for
とform_tag
があった。特にRubyチュートリアルでは2018/11/18現在、form_for
を利用した方法を紹介しています。が、5.1以降はform_with
推奨とのことなので、書き換えようと思いました。
form_with
APIドキュメントの翻訳版はこちらで読む事ができます。
基準となるモデルがある場合
チュートリアルでは7.2.1で登場してます。Userモデルを作るフォームです。
<%= form_for(@user) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %>
form_with
を使用すると下のようにかけます。基本的に変わりませんが、model:
でUserモデルを指定してあげます。チュートリアルの方を見ればわかりますが、コントローラの方で@user = User.new
やってます。
<%=form_with model: @user do |f|%> <%= render 'shared/error_messages', object: @user%> <%=f.label :name%> <%=f.text_field :name,class:'form-control'%> <%=f.label :email%> <%= f.email_field :email,class:'form-control'%> <%=f.label :password%> <%= f.password_field :password,class:'form-control'%> <%=f.label :password_confirmation %> <%=f.password_field :password_confirmation,class:'form-control'%> <%=f.submit yield(:button_text),class:'btn btn-primary'%> <%end%>
基準となるモデルがない場合
一方チュートリアル8.1.2では、上のような誰のフォームであるかをモデルで表わせず、session
という言葉でまとめています。
<%= form_for(:session, url: login_path) do |f| %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.submit "Log in", class: "btn btn-primary" %> <% end %>
これは下のようにして書き換えられます。
<%=form_with scope: :session, url:login_path do |f|%> <%=f.label :email%> <%=f.email_field :email, class:'form-control', id:'email'%> <%=f.label :password%> <%=f.password_field :password, class: 'form-control',id: 'password'%> <%=f.submit "Log in", class: "btn btn-primary"%> <%end%>
capybaraでのテスト
form_for
では、生成されるinputタグにid属性が付与されていました。一方form_with
ではid属性はオプションでつくようになっています。上の書き換えの例では、id属性にemail
とpassword
を指定しています。これはcapybaraでfill_in
メソッドを使用してテストするためです。(他にもテスト方法はありますが、、)
#form_for <input class="form-control" id="session_email" name="session[email]" type="email" /> #form_with(id指定なし) <input class="form-control" type="email" name="session[email]"> #form_with(id指定あり) <input class="form-control" id="email" type="email" name="session[email]">
fill_in
メソッドはidを参照するようで、id属性がないとエラーが起きます。変更前は以下のようにテストコードを書いていました。
#capybaraを使用しフォームに値を入れる fill_in "Email", with: "入力する値"
実はこれidがemail
だと反応しません。_email
かEmail
が含まれていれば反応します。 なので、どっちも小文字でemail
を指定するのが一番まるくおさまる気がします。もしくはid属性にEmail
を指定してやればテストコードはそのままで大丈夫かもしれません。