セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

【Ruby】チュートリアルのform_forをform_withで書き換え (おまけ:capybaraでのテスト)

//

Ruby5.1前まではフォームを生成してくれるメソッドとして、form_forform_tagがあった。特にRubyチュートリアルでは2018/11/18現在、form_forを利用した方法を紹介しています。が、5.1以降はform_with推奨とのことなので、書き換えようと思いました。

form_with

APIドキュメントの翻訳版はこちらで読む事ができます。

techracho.bpsinc.jp


基準となるモデルがある場合

チュートリアルでは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属性にemailpasswordを指定しています。これは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だと反応しません。_emailEmailが含まれていれば反応します。 なので、どっちも小文字でemailを指定するのが一番まるくおさまる気がします。もしくはid属性にEmailを指定してやればテストコードはそのままで大丈夫かもしれません。