質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.18%

[Rails]postアクションでパラメーターをURLに含めずに送信して、ビューを表示させる方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 511

takuan1108

score 56

ただいま、イベントを検索してチケットを購入できるアプリをRailsで作成しています。
ちょっと思ってたことができずに行き詰まってしまったので、、
もし良いアイディアがあれば教えていただけると嬉しいです!

実現したいこと

イベントのチケットを購入する際に、
申し込みフォームに名前やメールを入力して送信すると、
その後、フォームで入力したデータの「確認画面」が出てきて、
そこで確定ボタンを押して初めて購入処理がされるという、よくある機能を実現したいと思っています。

現在のコード

処理の流れは以下のような感じです。

①フォームに必要事項を入力させてpostメソッドで送信(※セキュリティの関係上getで送りたくない)

= form_with model: @guest, url: confirm_event_guest_path, method: :post, local: true do |f|
      = f.text_field :name
      = f.email_field :email
= f.submit "確認画面へ進む"


②アクションでparamsを受け取ったらrenderでビューを表示

  def confirm
    session[:guest] = guest_params
    render action: "confirm"
  end

  private
  def guest_params
    params.require(:guest).permit(:name, :email)
  end


③ルーティングは以下のようになっています

Rails.application.routes.draw do
  root to: 'events#index'
  resources :events do
    resource :guest, module:"events" do
      collection do
        post 'confirm'
        get 'done'
      end
    end
  end
end


※関係のない部分は一部省略して書いています。

問題点

実は上記コードでもURLにパラメーターを含めずに送信できて、ビューも表示することができています。
しかしながら、ビューを表示した後にブラウザの更新ボタン(F5)を押すとルーティングエラーになってしまいます。
そもそもconfirmアクションはルーティングではpostになっているので、
更新ボタンを押したらgetを探しに行って「そんなルーティングないよ!」となるのはわかるのですが…。

今のところの候補

Ajaxで非同期通信で送る?
form_withだからダメでform_forならいける?

開発環境

ruby '2.5.1'
rails '5.2.2'

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • maisumakun

    2019/04/24 15:36

    では、「ビューを表示した後に更新ボタンを押」した場合、どのような動作をさせたいのでしょうか?

    キャンセル

  • takuan1108

    2019/04/24 16:19

    ありがとうございます!
    更新ボタンを押しても、ルーティングエラーにならず、
    今いるページを再度表示させたいと思っています。

    キャンセル

  • asm

    2019/04/24 16:32

    更新ボタンとは、ブラウザのいわゆるF5でしょうか?
    それとも、ビュー側で「更新」と名のついたボタンを表示させているのでしょうか?

    キャンセル

  • takuan1108

    2019/04/24 16:59

    説明不足ですみません!
    ブラウザの更新ボタンのことになります。F5です。
    今はルーティングがpostであるconfirmアクション内で、
    無理やりrenderでビューを表示させるようにしているので、
    ブラウザの更新ボタンではgetメソッドを探しに行ってしまってルーティングエラーになってしまうんです。。

    キャンセル

回答 3

+2

しかしながら、ビューを表示した後にブラウザの更新ボタン(F5)を押すとルーティングエラーになってしまいます。

通常、「購入処理中にリロードなど、ブラウザの機能を使った移動はしないでください」の注意書きで済ませます。

きちんと対応しようとすれば相応の工数がかかりますが、対応したことによるメリットがさほど見込めないので、往々にして省略されます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/24 19:08

    ありがとうございます!
    めっちゃ経験ある方が仰ることなので、
    正攻法はないんだなと割り切りました笑

    一方少し足掻いてみて、
    post 'substitute'
    get 'confirm'
    として最初にpostに飛ぶようにして、
    その後リダイレクトさせるという方法をとってみまして、
    ブラウザの更新ボタンはエラーでなくなったのですが、
    今度は戻るボタンが戻りすぎてしまう現象が起こりましてギブアップでしたw

    素直に注意書きで済ませようと思います!
    ありがとうございました!

    キャンセル

  • 2019/04/25 20:35

    すみません!技術的な解決方法を見つけたので、
    そちらを今後の方のためにベストアンサーとさせていただきました。

    キャンセル

check解決した方法

0

解決方法を見つけたので共有します!
それはルーティングをgetとpostの2つ書くということです。

①同じconfirmアクションをgetとpostでルーティングに記述します。

Rails.application.routes.draw do
  root to: 'events#index'
  resources :events do
    resource :guest, module:"events" do
      collection do
        post 'confirm'
        get 'confirm'
        get 'done'
      end
    end
  end
end


②コントローラーではgetでもpostでも同じconfirmアクションが叩かれるので、
もし処理を分けたいならrequest.post?(またはrequest.get?)で分けます。

  def confirm
    if request.post?
      session[:guest] = guest_params
      render action: "confirm"
    end
  end

  private
  def guest_params
    params.require(:guest).permit(:name, :email)
  end

こうすることによってpostでパラメーターを送ることができ、
かつ、ブラウン座の更新ボタンが押されてgetでリクエストが飛んでもちゃんと表示されます!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

関係ない設定を削るときに欠落しただけかもしれませんが、 do~end が不足しているように思えます

resource :payment, module:"guests" do
  collection do
    post 'confirm'
  end
end

またAjax等に逃げても結局URL経由でのアクセスは変わらないので、URLが怪しいならまた問題が発生するでしょう
URL定義を確かめ根本の問題を解消すべきだと思います
routes.rb が実際にどんなURLになっているか確認してはどうでしょう?

bundle exec rake routes

※) 出力が多すぎて探しにくいなら grep で絞りましょう

bundle exec rake routes | grep payment

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/24 17:23

    回答ありがとうございます。
    rake routesはよく使っておりまして、
    今回post 'confirm'にした理由としては、
    form_forでpostメソッドで送りたかったからなんです。

    ですのでルーティングを、get 'confirm'とした上で、
    postメソッドでURLに含めずparamsを送れる方法があるのなら、
    その方がいいのですが。。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.18%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る