ひよっこエンジニアの雑多な日記

なんとかWeb系のエンジニアをやっています。

Rails 5.1のform_withを使ってうまくredirectできないあなたへ

かなり気まぐれですがネタができたらコンスタントにブログを投稿しようという気持ちになり始めました。
今年一年で50投稿を目指して頑張ります。

概要

Rails5.1 + sorceryを使って認証周りをサクッと作ろうとしたのですが、5.1から出てきたform_withに微妙にはめられました。
結構初歩的っぽいですが僕と同じような気持ちになる人がいるかもしれないので備忘録。
というかRailsの4.x系とか5.0系やってきた人が試しに5.1使ってみよってなったら割とハマるんじゃないかと勝手に思ったり…
※ ブログの内容的にはsorceryはもはや関与しません

事象

以下みたいな感じでログインフォームを作ってました。

<%= form_with url: sign_in_path, method: :post do %>
  <div class="field">
    <%= label_tag :email %><br />
    <%= text_field_tag :email %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag 'Login' %>
  </div>
<% end %>

これでログインできるか確認するためにLoginボタンを押すと

ログイン成功してるはずなのに画面遷移しない・・・・!!!

いやいやと思ってLoginボタンを連打してみるも状況は変わらず。
しかし画面再読み込みしたらログインできてる。

ログ見たら

Started POST "/sign_in" for 127.0.0.1 at 2017-07-08 23:03:12 +0900
Processing by UserSessionsController#create as JS

なんかJSをレンダリングしようとしてますやん!
そりゃ画面遷移しないわけだ。

解決策

ちゃんとform_withの仕様を把握してから使えばよかったのですが、解決策としてはなんてことない感じでした。
解決したコードがこちら

<%= form_with url: sign_in_path, method: :post, local: true do %>
  <div class="field">
    <%= label_tag :email %><br />
    <%= text_field_tag :email %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag 'Login' %>
  </div>
<% end %>

ほぼ変わってない感じですが、form_withlocal: trueオプションをつけてあげてます!
これでHTMLをレンダリングしてくれるので意図した動きになります!

どうもform_withはデフォルトで生成されるformタグにdata-remoteがついちゃうっぽいです。
local: trueを設定することでこれをつかないようにできるとのこと。

よくよく考えたらscaffoldで生成された_form.html.erbみるとform_withlocal: trueがついてんだよなあ
まあしかしこれで大人の階段をまた一つ登ることができました

余談

scaffoldで生成されるerbファイルのform_withのブロック変数がformになってるんですね!
いままではfがブロック変数でしたが、やはり可読性を考えると一文字よりも意味のある単語の方がよいんですかねえ