307
291

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsで入力の確認画面を出すときの定石

Posted at

よくあるお問い合わせフォームみたいので、ユーザーの入力を一度確認画面みたいな感じで表示してから送信したい時・・

  • ユーザーが問い合わせの入力
  • 「確認」ボタンをクリック
  • 入力した項目を一度確認画面に表示(入力とほとんど一緒)
  • 「送信」ボタンをクリック
  • 実際にモデルとして保存

という流れをRailsで実装する時の定石

Model

  • Question
app/models/question.rb
  validates :title, presence: true
  validates :name, presence: true
  validates :content, presence: true
  
  validates_acceptance_of :confirming
  after_validation :check_confirming

  def check_confirming
    errors.delete(:confirming)
    self.confirming = errors.empty? ? '1' : ''
  end

ここではDBに保存する値は、 title, name, content とする。(必須入力)
validates_acceptance_of はRailsの機能。

validates_acceptance_of - リファレンス - - Railsドキュメント

confirmingはDBに保存しなくて大丈夫。

ポイントは次の2点

  • validate_accepttance_ofが指定してあるので、confirmingの値が存在するかのバリデーションチェックが発生
  • 一度validationした後に after_validation で指定されているメソッドがコールされる。この時confirming以外にエラーがない場合は、チェック済として値をセット

Controller

応答するコントローラーメソッド

RESTに従う

  • 新規質問入力画面を表示 : QuestionsController#new (GET)
  • 確認ボタンクリックに応答 : QuestionsController#create (POST)
  • 入力内容を確認する画面を表示 : QuestionsController#new (GET)
  • 送信ボタンクリックに応答 : QuestionsController#create (POST)

ポイントはmodelのconfirmingのバリデーション機能で、上手いことページ遷移を発生させてるとこ。

app/controllers/questions_controller.rb
class QuestionsController < ApplicationController

  def new
    @question = Question.new
  end

  def create
    @question = Question.build(question_params)
    
    respond_to do |format|
      if @question.save
        format.html { redirect_to @question, notice: '質問を送信しました。' }
      else
        # 一度目の「確認」ボタンクリック時は、confirmingがセットされていないのsaveでエラーが発生しこっちに来る
        # ただし、ここに到達した時点で model の after_validation 後なので、confirmingはセットされている状態で new アクションへ
        format.html { render action: 'new' }
      end
    end
  end

  private
  
  def question_params
    params.require(:question).permit(:title, :name, :content, :confirming)
  end
end

View

同じフォームで confirming 値の有無で、画面表示を分岐させる。
(入力項目と確認項目はinputか単なるテキストかの違いだけで、ほぼ同一なので、一緒のテンプレートにある方がわかりやすい)

(simple_form gemを使っている)

app/views/questions/_form.html.haml
= simple_form_for @question do |f|
  - if @question.confirming.blank?
    .form-inputs
      = f.input :name, label: 'お名前'
      = f.input :title, label: 'ご質問'
      = f.input :content, label: 'ご質問内容'
    .form-actions
      = f.button :submit, '内容を確認する'
  - else
    %table.table
      %tr
        %th お名前
        %td= @question.name
      %tr
        %th ご質問
        %td= @question.title
      %tr
        %th ご質問内容
        %td= @question.content
    
    .form-inputs
      = f.hidden_field :name
      = f.hidden_field :title
      = f.hidden_field :content
    .form-actions
      %p この内容でご質問メールを送信します。よろしいですか?
      = f.button :submit, '送信する'
  
  = f.hidden_field :confirming  

2回目の「送信」ボタンでは、ユーザー入力のパラメータはhiddenで渡す。

307
291
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
307
291

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?