Railsで新規作成/編集の確認画面を作る

## はじめに
確認画面の情報は既にいくつも公開されていますが、編集の際の確認画面に関しては、あまり見当たらなかったため記事にしました。

### 開発環境
- Rails 6.0.3.1
- Ruby 2.6.8

### やりたいこと
既に新規登録/編集機能があるアプリにて、それぞれ投稿の前に確認画面を挟みたい。
今回は、`title`と`content`というカラムを持つ`Blog`モデルに関して実装していく。

## 新規投稿の確認画面
### Controllerの実装

新規投稿の際のcontrollerは以下のようになります。

```blog_controller.rb
	def new
		@blog = Blog.new
	end

	def confirm
		@blog = Blog.new(blog_params)
		render :new if @blog.invalid?
	end

	def create
		@blog = Blog.new(blog_params)

		if params[:back] || !@blog.save
			render :new
		else
			redirect_to blogs_url, notice: "#{@blog.title}を投稿しました。"
		end
	end

```

`new`と`create`アクションは、Railsのチュートリアル等のまんまです。
追加点として、
1. `confirm`アクションを定義し、内部で値が不正だったら、`new`にレンダリングする
2. `create`アクションでは、`params[:back]`という値があるとき、もしくはblogが保存できなかったとき、`new`にレンダリング、そうでない時は一覧画面へリダイレクトする。この時の`params[:back]`は後ほど、view側で設定。
の上記２点です。

### Viewの実装
ビューでは新しく`app/views/blogs/confirm.html.erb`を作成します。
中身は、ブログの各カラムが確認できるshowのようなものと、投稿/修正するボタンを含めたフォームになっています。

```confirm.html.erb

<h1>
  <%= @blog.title %>
</h1>

<p>
  <%= @blog.content %>
</p>

<%= form_with model: @blog, local: true do |f| %>
  <%= f.hidden_field :title %>
  <%= f.hidden_field :content %>
  <%= f.submit "投稿する" %>
  <%= f.submit "修正する", name: "back" %>
<% end %>

```
ポイントとしては、
1. 修正に戻るsubmitボタンに、name属性として`back`を指定する
2. title, contentをhidden_fieldとしてユーザーから編集できない形で再度サーバー側に送るようにする
の２点です。確認画面から編集内容をサーバーに送る方法としては、hidden_fieldで値を隠す方法、sessionを用いる方法の2つが挙げられますが、パスワードや管理者権限等の値を取り扱っていないため、今回はhidden_fieldを用いています。
sessionを用いる方法に関しては、[こちら](https://web-begginer-log.com/rails-confirm/#toc10)のサイトなどをご参考ください。

続いて、app/views/blogs/new.html.erbのformの送り先もconfirmに設定し直します。

```new.html.erb
<%= form_with model: @blog, url: confirm_blogs_url(@blog), local: true do |f| %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.label :content %>
    <%= f.text_area :content %>
  </div>
  <%= f.submit "投稿する" %>
<% end %>
```
formタグのurlにて、送り先が変更されている点にご注意ください。

### routes.rbの編集
最後に、ルーティングを設定して、実装完了です。
ルーティングは、resourcesを用いている場合は、以下のようになります。

```routes.rb
  resources 'blogs' do
    collection do
      post 'confirm'
    end
  end
```

## 編集の確認画面
ここまでで新規投稿の確認画面に関して、実装してきましたが、ここから編集の確認画面を実装していきます。
と言っても、被っている点が非常に多いので、説明は簡潔にしていきたいと思います。

### Controllerの実装

```blogs_controller.rb
	def edit
		@blog = Blog.find(params[:id])
	end

	def edit_confirm
		@blog = Blog.find(params[:id])
		@blog.attributes = blog_params
		render :edit if @blog.invalid?
	end

	def update
		@blog = Blog.find(params[:id])
		if params[:back] || !@blog.update(blog_params)
			render 'edit'
		else
			redirect_to blogs_url, notice: "#{@blog.title}を編集しました。"
		end
	end

```
ほとんど新規投稿の際のアクションと同様ですが、attributesメソッドを用いて、値の更新をしていることにご注意ください。また、編集の性質上、idが必要なため新規投稿と編集でconfirmを違うアクションとして設定しています。

### Viewの実装
Viewもほとんど新規投稿と同じです。

```edit_confirm.html.erb

<h1>
  <%= @blog.title %>
</h1>

<p>
  <%= @blog.content %>
</p>

<%= form_with model: @blog, local: true do |f| %>
  <%= f.hidden_field :title %>
  <%= f.hidden_field :content %>
  <%= f.submit "投稿する" %>
  <%= f.submit "修正する", name: "back" %>
<% end %>

```

```edit.html.erb
<%= form_with model: @blog, url: edit_confirm_blog_url(@blog), local: true do |f| %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.label :content %>
    <%= f.text_area :content %>
  </div>
  <%= f.submit "投稿する" %>
<% end %>

```
urlの違いにご注意ください。

### routes.rbの編集
最後に、ルーティングを設定して、実装完了です。
編集の際にはidが必要なため、memberの中に追加します。

```routes.rb
  resources 'blogs' do
    collection do
      post 'confirm'
    end
    member do
      patch 'edit_confirm'
    end
  end
```

## 参考記事に関して
公式ガイド等の他に以下の記事を参考に、執筆させていただきました。
- [【Ruby on Rails】確認画面を作る方法！hiddenか？セッションか？](https://web-begginer-log.com/rails-confirm/)
- [rails で確認画面作成
](https://qiita.com/tomoharutt/items/7959d28764912c64562f)