Help us understand the problem. What is going on with this article?

Railsチュートリアルでform_withを使う

概要

Rails5.1から「form_forヘルパー」と「form_tagヘルパー」が非推奨になっていると知ったので、新たに導入された「form_with」を使用しようとしたが少し手間取ったのでメモ。
解決までの内容に興味がなければ「解決方法」に最終的なコードがあるので他は読み飛ばしてください。

実現したいこと

Railsチュートリアル7章、リスト7.15および完成系のリスト7.27を「form_with」を使用して実装する。

リスト7.15
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= 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 %>
  </div>
</div>
リスト27
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: signup_path) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= 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, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

発生したエラー

まず、リスト7.15を(コード1)のように書き換えて実装。

コード1
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user) do |f| %>   <%# この行のみ変更 %>
      <%= f.label :name %>

<%# 後略 %>

問題なくブラウザには表示されたが、チュートリアルを進めると「図 7.15: ユーザー登録失敗」が表示されない。
ん?と思いコンソールを確認すると(図1)のように表示されていた。

図1
Started POST "/users" for ::1 at 2020-03-01 20:07:59 +0900
   (0.5ms)  SELECT sqlite_version(*)
   (0.2ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by UsersController#create as JS
  Parameters: {"authenticity_token"=>"1kulZpjCeawCkV6pT76gpjkNMJKKZCgx5x2xOfZz6ftXd+oLZX7UMjRRejscuv4kSEIHcPGh86nlR7FR9Fz/Uw==", "user"=>{"name"=>"", "email"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"登 録"}
Completed 500 Internal Server Error in 12ms (ActiveRecord: 0.8ms | Allocations: 5794)
ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):

なんでブラウザに表示されないんだろうと疑問に感じながらも

ActiveModel::ForbiddenAttributesError

の一文があるのでチュートリアルと同様のエラーは発生していると判断してそのまま進める。

すると「図 7.18: ユーザー登録失敗時のエラーメッセージ」も表示されない!?
さすがにこれは問題だと思いあれこれ調べるとform_withはデフォルトでは非同期通信(Ajax)になっているという。
(図1)のエラーメッセージのこの一文で判断できたらしい。

Processing by UsersController#create as JS #JavaScriptとして処理する(?)

解決方法

最終的なコードが(コード2)

コード2
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, url: signup_path, local: true) do |f| %> <%# この行のみ変更 %>
      <%= render 'shared/error_messages' %>

      <%= 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, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

form_withを同期通信にするにはオプションで

local: true

を加えればOK!

後書き

ちゃんと学習してから使用していればこんな初歩的なつまずきはなかったのでしょう。
常に変化し続けるこの業界では学び続けることが本当に大切なんだなと実感した出来事でした。

chabudai
Rails学習者。細かいエラーなんかに囚われてなかなか前に進めないのですが、そのぶん成長できると信じて格闘中。
https://w-muro.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away