はじめに
createアクションでインスタンスを生成する際に、いったん確認画面を挟んで修正点がなければcreateアクションを実行するという仕様のアプリを作成したので備忘録としてまとめたいと思います!
イメージGifのように
① 各項目を入力して「確認へ」を押す
↓
② 確認画面で確認したら「送信」を押す(修正箇所があれば入力画面に戻る)
↓
③ 完了画面へリダイレクト
この流れでインスタンスを保存していきます。
前提(開発環境)
- macOS Catalina
- Ruby 2.6.5
- Ruby on Rails 6.0.0
- Visual Studio Code
- データベース: Mysql
- テンプレートエンジン: haml
目次
1.ルーティング
2.モデル
3.コントローラー
4.ビュー
1. ルーティング
今回はeventというインスタンスを作成するという設定で実装を進めます。
そのためER図は以下の通りです。
イベントモデルがユーザーモデルに紐付いており、イベントモデルのカラムには全てバリデーションを設定しています。
このeventモデルはpostでもtweetモデルでも任意のもので構いません。
それでは、本題に入ります。
Rails.application.routes.draw do
root to: 'events#index'
resources :events, only: [:index, :new, :create, :show] do
collection do
post :confirm
end
end
end
通常はnew
でイベント作成画面に遷移してcreate
すればイベント一覧に遷移するという仕様ですが、
今回は確認画面を挟むためnew
→confirm
→create
の順にアクションを実行します。
独自のアクションを設定する際は個別のidが必要ない場合はこのようにcollection
をネストさせます。
2. モデル
class Event < ApplicationRecord
with_options presence: true do
validates :event_name
validates :datetime
validates :prefecture
validates :place
validates :detail
end
end
# 空のバリデーションを設定
3. コントローラー
class EventsController < ApplicationController
def new
@event = Event.new
end
def confirm
@event = Event.new(event_params)
if @event.invalid? #入力項目に空のものがあれば入力画面に遷移
render :new:
end
end
def create
@event = Event.new(event_params)
@event.user_id = current_user.id
if params[:back] || !@event.save #戻るボタンを押したときまたは、@eventが保存されなかったらnewアクションを実行
render :new and return
redirect_to root_path
end
def show
@event = Event.find_by(id: params[:id])
end
private
def event_params
params.require(:event).permit(:event_name, :datetime, :prefecture, :place, detail)
end
end
ポイントは、アクションを移動する度にインスタンス情報の入ったパラメーターを渡しているところです。
ここでいうEvent.new(event_params)
のところです。ここに全てのインスタンス情報が入っているので、new
→confirm
に遷移しても情報が保持されます。
そして戻るボタンを押した時の挙動も、params[:back]で制御しています。backが渡ってきたら前の画面にrenderすればOKです。
4. ビュー
new画面
= form_with(model: @event, url: confirm_events_path(@event), local: true, id: "new-event") do |f|
.top-area
.create-item-1
= f.label :event_name, "イベント名", class: "Form-label"
= f.text_field :event_name, maxlength: "50", class: "name-field"
.middle-area
.create-item-2
= f.label :datetime, "開催日時", class: "Form-label"
= f.date_field :datetime, class: 'form-control', class: "middle-field"
.create-item-2
= f.label :tag_list, "タグ付け"
= f.text_field :tag_list, value: @event.tag_list.join(','), placeholder: "ダンス,東京,・・・", class: "middle-field"
.bottom-area
.create-item-3
= f.label :prefecture, "開催場所(都道府県)", class: "Form-label"
= f.select :prefecture, Event.prefectures.keys, {}, class: "place-field"
.create-item-3
= f.label :place, "開催場所(詳細)", class: "Form-label"
= f.text_field :place, maxlength: "30", class: "place-field"
.create-item-4
= f.label :detail, "イベント詳細説明", class: "Form-label"
= f.text_area :detail,, class: "detail-area"
.create-btn-field
= f.submit "確認画面へ", class: "create-btn"
ポイントは, URL指定でconfirm_events_pathへリクエストを投げていることです。
有効であればconfirmアクションへ移動して次の確認画面ではEvent.new(user_params)が表示されるので状態が維持されます。
パスの指定のhamlの記述は自分好みでカスタマイズしてください。
confirm画面
%h2.please-check
以下の内容を確認してください
.confirm-contents
.confirm-contents__item
%p.item-heading
イベント名:
%p.item-content
= @event.event_name
.confirm-contents__item
%p.item-heading
開催日時:
%p.item-content
= @event.datetime.strftime("%Y年%-m月%-d日")
.confirm-contents__item
%p.item-heading
開催場所(都道府県):
%p.item-content
= @event.prefecture
.confirm-contents__item
%p.item-heading
開催場所(詳細):
%p.item-content
= @event.place
.confirm-contents__item
%p.item-heading
タグ:
%p.item-content
= @event.tag_list
.confirm-contents__item
%p.item-heading
イベント詳細:
%p.item-content
= @event.detail
= form_with(model: @event, local: true, id: "confirm-event") do |f|
= f.hidden_field :event_name
= f.hidden_field :datetime
= f.hidden_field :prefecture
= f.hidden_field :place
= f.hidden_field :detail
= f.hidden_field :tag_list
= f.submit "作成", class: "complete-btn"
= f.submit "修正", name: :back, class: "back-btn"
ポイントは2つです。
①new画面のformの項目をhiddenにしておく
new画面でのインスタンスをもっていきたいので、confirm
のviewでもformを記述します。
しかし、formが見えてお邪魔なので、hiddenにしておきます。
②修正ボタンの設定
戻るボタンはnameでパラメータを指定して、アクション側で存在すれば前の画面にrenderしてあげます。
無事インスタンスが保存されれば、イベント一覧画面にリダイレクトされます!
おわりに
さいごまで読んでいただきありがとうございました!
お疲れさまでした。。