form_withでredirect_toがページ遷移しない時の原因

【結論】

・form_withはデフォルトでremote: true
 というオプションが設定されている

・remote: trueを設定すると
 フォーム送信を非同期通信で実行できるが、
 ページ遷移されなくなるので、
 redirect_toが機能しなくなる

・この場合、local: trueというオプションを
 設定すれば解決する

【目次】

【本題】

form_withを初めて使って見た

今まで、フォームの生成には
「form_tag」「form_for」を利用してきましたが、
新たに「form_with」を使ってみることにしました。

というのも、Rails5.1以降は、「form_tag」「form_for」が
非推奨となっており、いずれ「form_with」に統合される見通しの為です。

なお「form_with」は、「form_tag」「form_for」の
いいとこ取りをした様なビューヘルパーです。

という訳で、全く仕様を理解しないまま使っていると、
思わぬところでつまづいたので、今回はそれをまとめます。

redirect_toでページ遷移できない

「form_with」で下記の様な
新規登録フォームを実装しました

def create
    @request = request.new(request_params)
    if @request.save
        redirect_to requests_path
    else
        render :new
    end
end

正常に保存が完了すれば、redirect_toで
指定したパスに飛ぶ様な記述になっています。

ところが、登録操作をしても全くページ遷移しません。
データベースには正常にデータが保存されており、
更にbinding.pryを設置して確認すると、
trueでIF文が分岐している事が分かりました。

原因が特定できず、現場のメンターに
確認すると、「form_with」が原因である事が分かりました。

オプション remote: trueについて

その理由は、「form_with」には、
「 remote: true」というオプションが設定されている事です。

「remote: true」とは、リクエストを
HTML形式ではなく、JS形式で送信するオプションです。

これにより、フォーム送信が非同期通信で実行されます。
但し、非同期通信でリクエストを送った場合、
redirect_toが設定されていても、ページ遷移はなされません。

この仕様により、データは保存されているにも関わらず
ページが遷移しないという問題が発生していたのです。

実際に、先ほどのコードを実行した直後の
処理結果をターミナルで確認すると、
下記の様なJS形式になっていました

Started POST "/request/1" for 127.0.0.1 at 2019-03-26 18:38:00 +0900
Processing by RequestsController#create as JS

HTML形式の場合、下記の様になります。

Started POST "/request/1" for 127.0.0.1 at 2019-03-26 18:38:00 +0900
Processing by RequestsController#create as HTML

解決策:local: trueの設定

この問題を解決するには、
「form_with」に「local: true」という
オプションを設定します。

これにより、フォームの送信は
同期通信に切り替わるので、ページ遷移が可能となります。

 <%= form_with model: @request ,local: true  do |f| %>