Railsの form_with を用いた投稿の作成と編集の処理の流れ① pryを使用してインスタンスの中身も確認してみる。

:::note warn
現在、プログラミングスクールにて、主にRubyやRuby on Railsを勉強している者です。この記事を通して少しでもお役に立てられますと幸いです。また、説明不足や誤りがございましたら申し訳ございません。
:::

## 前提
- MVCの流れや一対多の関連付けについての多少の理解。
- Sorcery gemを使用しているため、current_userメソッドを使っています。
- 機能は最低限となっているため、パーシャル（フォーム用）等は使用しておりません。
- ルーティングは resources :posts を使用しており、標準的なRESTfulルートが生成されています。

```ruby:app/config/routes.rb
Rails.application.routes.draw do
  resources :users, only: %i[new create]
  resources :posts
end
```

```
# 今回使用されるルーティング

posts_path	GET	/posts(.:format) posts#index
            POST /posts(.:format) posts#create
new_post_path	GET	/posts/new(.:format) posts#new
```

## 実行環境
Ruby 3.2.2
Rails 7.0.8

# 新規投稿の流れ
![スクリーンショット 2024-01-14 18.05.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535583/f70b2cb6-e301-4fe9-1288-d6d4cf1e3d1e.png)
新規投稿の流れは、（今回は）ヘッダーにある「新規投稿」リンクのクリックから始まります。
```erb:app/views/share/_header.html.erb
<h1 class="text-xl font-semibold">多機能掲示板</h1>
<nav>
  <ul class="flex space-x-6">
    <%= link_to '新規投稿', new_post_path, class: "hover:text-blue-300 transition-colors duration-300" %>
    <%= link_to '投稿一覧', posts_path, class: "hover:text-blue-300 transition-colors duration-300" %>
    <%= link_to 'ログアウト', logout_path, class: "hover:text-blue-300 transition-colors duration-300", data: { turbo_method: :delete } %>
  </ul>
</nav>
```
## new アクションの実行
new_post_path（新規投稿リンク） をクリックすると、ブラウザは GET メソッドで PostsController の new アクションをリクエストして、結果として関連するnew.html.erbをブラウザにレスポンスとして返します。
このアクションでは、新しい投稿を作成するための空の Post インスタンスが生成され、これが入力フォーム（form_with ヘルパーを使用）に渡されます。

```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def new
    @post = Post.new
  end
end

```
@post = Post.new は、データベースに保存されていない新しい Post オブジェクト（インスタンス）を作成します。このオブジェクト（インスタンス）は、後ほど出てくるform_withヘルパーを使用した入力フォームにて、ユーザの入力を受け付けるために必要となってきます。

## binding.pryを使用して、postインスタンスの中身を確認してみる。
```ruby
    6: def new
    7:   binding.pry
 => 8:   @post = Post.new
    9: end

[1] pry(#<PostsController>)> @post = Post.new
=> #<Post:0x0000000******
 id: nil,
 title: nil,
 description: nil,
 user_id: nil,
 created_at: nil,
 updated_at: nil>
[2] pry(#<PostsController>)> 
``` 
値のセットされていない空のpostインスタンスが生成されていることが確認できます。

## 新規投稿フォーム
![スクリーンショット 2024-01-14 18.08.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535583/ba56338a-1aa4-e95d-a562-e15d7ee154a4.png)

new.html.erb ビューには、form_with ヘルパーを使用したフォームが含まれています。ユーザーがこのフォームに入力し、登録 ボタンをクリックすると、フォームに入力されたデータは PostsController の create アクションに送信されます。

```erb:app/views/posts/new.html.erb
<%= form_with model: @post do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.label :description %>
  <%= f.text_area :description %>
  <%= f.submit '登録' %>
<% end %>
```

:::note info
なぜcreateアクションに送信されるのか？

form_withヘルパーは、データ送信先のURLを自動的に決定する機能を持っています。上記のように、form_with model: @post の場合、Railsはnewアクションで生成した@post の状態が新規レコードであるか既存のレコードであるかどうかを調べ、新規の場合は、createアクションで、既存の場合はupdateアクションに送信する流れとなっています。
:::

## createアクション
![スクリーンショット 2024-01-14 18.11.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535583/a18f661d-0ab8-4d9d-6d82-fbb2424756d3.png)
create アクションは、新規投稿フォームから送信されたデータを処理します。form_with により送信されたデータは、このアクションで受け取られ、新しい Post インスタンスに割り当てられます。
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  # ...[他のアクション]...

  def create
    @post = current_user.posts.build(post_params)
    if @post.save
      redirect_to posts_path, notice: '投稿が正常に作成されました。'
    else
      render :new
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :description)
  end
end
```
ここでは、post_params メソッドを使用してフォームから送信されたデータを安全に扱います。@post.save が成功すると、ユーザーは投稿一覧ページにリダイレクトされ、失敗した場合は新規投稿フォームが再表示されます。

## binding.pryをcreateアクションに挟んで、中身を確認してみる。
```ruby
    10: def create
    11:   binding.pry
 => 12:   @post = current_user.posts.build(post_params)
    13:   
    14:   if @post.save
    15:     redirect_to posts_path
    16:   else
    17:     render :new
    18:   end
    19: end

[1] pry(#<PostsController>)> params
=> #<ActionController::Parameters {"authenticity_token"=>"VTxLfc*****", "post"=>{"title"=>"テスト", "description"=>"テスト2"}, "commit"=>"登録", "controller"=>"posts", "action"=>"create"} permitted: false>
[2] pry(#<PostsController>)> @post = current_user.posts.build(post_params)
=> #<Post:0x000000**********
 id: nil,
 title: "テスト",
 description: "テスト2",
 user_id: 1,
 created_at: nil,
 updated_at: nil>
[5] pry(#<PostsController>)> if @post.save
[...]
=> #<Post:0x0000000**********
 id: 8,
 title: "テスト",
 description: "テスト2",
 user_id: 1,
 created_at: Sun, 14 Jan 2024 08:26:36.718209000 UTC +00:00,
 updated_at: Sun, 14 Jan 2024 08:26:36.718209000 UTC +00:00>
```
ここで、@post.save の実行後、新しい投稿データがデータベースに正常に保存されたことが確認できます。この結果、生成された @post インスタンスには、一意のID、タイトル、説明文、ユーザーID、そして作成日時と更新日時が割り当てられています。これにより、新規投稿のプロセスが完了しました。

:::note info
補足：params メソッドについて
params メソッドは、コントローラ内でHTTPリクエストから送信されたパラメータを取得するために使用されます。
このメソッドは、フォームやURLからの入力を含むリクエストパラメータを扱います。今回の例では、フォームでユーザーが入力したデータ（タイトルと説明文）が params に含まれており、これらは post_params メソッドを通じて安全に抽出・利用されます。

※詳しくは同じスクールに通っている方が、paramsについて詳しく記事にしているので、ご参照いただけますと幸いです。
:::
https://zenn.dev/hime/articles/7101cc7110fef9

:::note info
newアクションで生成されたインスタンスは使用することはできないのか。

Railsでは、各HTTPリクエストは独立しており、一つのアクションで生成されたインスタンス変数（例えば @post = Post.new）はそのリクエストのスコープ内でのみ有効です。つまり、new アクションで生成された @post インスタンスは、create アクションでは直接利用できません。

そのため今回の例では、create アクションで、新たにcurrent_user.posts.build(post_params) を用いて、フォームから送信されたデータに基づいて新しいインスタンスを作成する必要があります。
:::

以上が、Railsの form_with を用いた投稿の作成の流れとなります。
説明ができてない部分や言語化ができてない部分が多々あるかと思いますが、少しでも参考になりますと幸いです。
実際にはさまざまなオプションだったり使用方法がありますので、詳しくはRailsガイド等を参照願います。

ご拝読いただき、ありがとうございました。編集の流れは次回書きたいと思います。

## 資料
https://zenn.dev/hime/articles/7101cc7110fef9

https://railsguides.jp/form_helpers.html