Railsで入力画面→確認画面→送信完了までの実装

こんにちは!kossyです!




さて、今回は、Railsで入力画面→確認画面→送信完了までの実装方法を
ブログに残したいと思います。

f:id:kossy-web-engineer:20181018224559p:plain
写真のような画面を作りたいとして、
項目が多いため、確認画面への遷移を行いたいとする。


post先はconfirmを指定します。

form.html.haml

= form_for :proposal, url: confirm_proposals_path do |f|
  省略

routes.rb

  resources :proposals, only: [:new] do
    collection do
      post :confirm
    end
  end


$ rails routes
confirm_proposals POST   /proposals/confirm(.:format)     proposals#confirm
     new_proposal GET    /proposals/new(.:format)         proposals#new

投稿画面に入力された値のバリデーションは、
確認画面に遷移する前に確認します。

proposals_controller.rb

class ProposalsController < ApplicationController
  before_action :proposal_params, only: [:confirm]

  def new
    @proposal = Proposal.new
  end

  def confirm
    return if @proposal.valid?
    render :new
  end

private

  def proposal_params
   @proposal = Proposal.new(params.require(:proposal).permit(:name, :email, :phone_number, :perfecture, 以下省略))
  end

end

確認画面サンプル
f:id:kossy-web-engineer:20181018225714p:plain

入力画面へ戻るボタンを押したら、値を保持したまま
戻りたいので、hidden_fieldで渡します。

入力された値に間違いがなければ、そのままDBへ保存したいので、
これもhidden_fieldで渡します。

以下サンプルコード

confirm.html.haml

= form_for :proposal, url: new_proposals_path do |f|
  = f.hidden_field :name
  = f.hidden_field :email
  = f.hidden_field :phone_number
省略
  = f.submit '入力画面へ戻る'

= form_for :proposal, url: proposals_path do |f|
  = f.hidden_field :name
  = f.hidden_field :email
  = f.hidden_field :phone_number
省略
  = f.submit '登録する'

戻るボタンが押された時のルーティングとアクションを定義します。

proposals_controller.rb
class ProposalsController < ApplicationController
  before_action :proposal_params, only: [:confirm, :back]
省略

  def back
    render :new
  end

  省略
end

routes.rb

resources :proposals, only: [:new] do
    collection do
      post :new, path: :new, as: :new, action: :back
      post :confirm
    end
  end

pathとasを指定しているのは、createとpathメソッド名が重複し動作しなくなるため指定しています。


最後にcreateアクションを追加します。

proposals_controller.rb
class ProposalsController < ApplicationController
  before_action :proposal_params, only: [:confirm, :back, :create]
  省略

def create
    if @proposal.save
      redirect_to root_path
      flash[:notice] = "申し込みが完了しました。2営業日以内にご連絡を致します。"
    else
      render :new
    end
  end

  省略
end


routes.rb
  resources :proposals, only: [:new, :create] do
    collection do
      post :new, path: :new, as: :new, action: :back
      post :confirm
    end
  end

これで入力画面→確認画面→送信完了の動きを実現できると思います。



以下サンプルコードを掲載します

form.html.haml

  = form_for :proposal, url: confirm_proposals_path do |f|
    %ul
    - @proposal.errors.full_messages.each do |message|
      %li= message
    .form-group
      = f.label '氏名'
      = f.text_field :name, class: 'form-control', placeholder: '氏名を入力してください'
    .form-group
      = f.label 'メールアドレス'
      = f.text_field :email, class: 'form-control', placeholder: 'メールアドレスを入力してください'
    .form-group
      = f.label '電話番号'
      = f.text_field :phone_number, class: 'form-control', placeholder: '例: 090-1234-5678'
  省略
    = f.submit '入力確認画面へ', class: "btn btn-primary"


confirm.html.haml
%h1.pt-5.mt-5
  入力事項確認画面
%table.table.table-striped.pt-5.mt-5
  %tr
    %th 氏名:
    %td= "#{@proposal.name}"
    %th メールアドレス:
    %td= "#{@proposal.email}"
  %tr
    %th 電話番号
    %td= "#{@proposal.phone_number}"
  省略

= form_for :proposal, url: new_proposals_path do |f|
  = f.hidden_field :name
  = f.hidden_field :email
  = f.hidden_field :phone_number
  省略
  = f.submit '入力画面へ戻る'

= form_for :proposal, url: proposals_path do |f|
  = f.hidden_field :name
  = f.hidden_field :email
  = f.hidden_field :phone_number
  省略
  = f.submit '登録する'


routes.rb
  resources :proposals, only: [:new, :create] do
    collection do
      post :new, path: :new, as: :new, action: :back
      post :confirm
    end
  end


$ rails routes

    new_proposals POST   /proposals/new(.:format)     proposals#back
confirm_proposals POST   /proposals/confirm(.:format) proposals#confirm
        proposals POST   /proposals(.:format)         proposals#create
     new_proposal GET    /proposals/new(.:format)     proposals#new


proposals_controller.rb
class ProposalsController < ApplicationController
  before_action :proposal_params, only: [:confirm, :back, :create]

  def new
    @proposal = Proposal.new
  end

  def confirm
    return if @proposal.valid?
    render :new
  end

  def back
    render :new
  end

  def create
    if @proposal.save
      redirect_to root_path
      flash[:notice] = "申し込みが完了しました。2営業日以内にご連絡を致します。"
    else
      render :new
    end
  end

  private

  def proposal_params
   @proposal = Proposal.new(params.require(:proposal).permit(:name, :email, :phone_number 省略))
  end

end