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| %>