概要
Rails事始めで、フォームから送信した内容を反映させるだけのことが「ページがレンダリングされない」という状態になった話。
結論はfome_with
の機能とパラメーターに関するもので、オンラインレッスンの講師の方に教わるまで解決できなかった。
問題の内容
アプリケーション
フォームから受け取った値をインスタンス変数に入れて、それを他のアクションで参照してフォームがあるページを更新するという内容。
躓いてから、できるだけシンプルにしていったのが次のアプリケーションで、フォームのボタンを押すとトップページのテキストの内容を入れ替えるだけのもの。
コントローラー:app/controllers/pages_controller.rb
1 2 3 4 5 6 7 8 9 10 |
class PagesController < ApplicationController def top @text = "Hello" end def input @text = "Hi" render action: :top and return end end |
ビュー:app/views/pages/top.html.erb
1 2 3 4 5 6 7 8 |
<h1>Top Page</h1> <% p @text %> <p>Text:<%= @text %></p> <%= form_with(url: input_path) do |f| %> <button>Submit</button> <% end %> |
ルーティング:config/rotes.rb
1 2 3 4 |
Rails.application.routes.draw do root to: 'pages#top', as: :top post 'input', to: 'pages#input', as: :input end |
症状
以下のページが表示されるが、Submitボタンを押しても画面に変化がない。
よく見ると、inputにルーティングしているのにURLに/inputがついていない。
検証ツールで見ると、inputに対して通信はしていて、書き換えの処理はされているようだ。
コンソールの出力を見ると、POST時の変数の内容は”Hi”に変更されている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Started GET "/" for 10.0.2.2 at 2021-03-14 15:36:51 +0900 Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by PagesController#top as HTML Rendering pages/top.html.erb within layouts/application "Hello" Rendered pages/top.html.erb within layouts/application (0.8ms) Completed 200 OK in 18ms (Views: 16.6ms) Started POST "/input" for 10.0.2.2 at 2021-03-14 15:36:57 +0900 Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by PagesController#input as JS Parameters: {"utf8"=>"✓", "authenticity_token"=>"Ok8wUxj2qkkQHCk/gn6vsH0fib/NlpZgiS9NCM9w2iVSc/gEZ4BQCY7EHFJ9WHmUhaR/LxiIFYFlUMSOeIs/eg=="} Rendering pages/top.html.erb within layouts/application "Hi" Rendered pages/top.html.erb within layouts/application (1.0ms) Completed 200 OK in 36ms (Views: 35.8ms) |
解決
解決策は”form_withのパラメーターにlocal: trueを加える”というものだった。
<%= form_with(url: input_path, local: true) do %>
コントローラー:app/controllers/pages_controller.rb
1 2 3 4 5 6 7 8 |
<h1>Top Page</h1> <% p @text %> <p>Text:<%= @text %></p> <%= form_with(url: input_path, local: true) do |f| %> <button>Submit</button> <% end %> |
Submitボタンを押すと表示が変更されるようになった。
理由
form_for
では送信時にページ全体がレンダリングされるが、form_with
はデフォルトではajaxによる送信となっていて、そのままではページがレンダリングされない。
パラメーターにlocal: true
を指定するとHTMLとしてのフォーム送信として扱われ、ページがレンダリングされる。
form_tag/form_with
がdeprecatedだというところだけを読んで気軽に使ったのが敗因。