Railsアプリで編集機能を実装する

#編集機能の実装
編集機能では、既に登録された投稿の属性の値を変更してDBに保存します。
一覧画面の投稿情報ごとに「編集」リンクが表示され、そのリンクから編集画面へ遷移することにします。
また、詳細画面にも編集ボタンを設けるようにします。

##編集リンクの設置
まずは一覧画面(app/views/posts/index.html.slim)に編集画面へのリンクを設置します。
編集画面はedit_post_pathというヘルパーメソッドにより、post/[投稿ID]/editというURLを生成できます。

```ruby:app/views/posts/index.html.slim
h1 タスク一覧

= link_to '新規投稿', new_post_path, class: 'btn btn-primary'

.mb-3
table.table.table-hover
  thead.thead-default
    tr
      th= Post.human_attribute_name(:content)
      th= Post.human_attribute_name(:created_at)
      th
  tbody
    - @posts.each do |post|
      tr
        td= link_to post.content, post
        td= post.created_at
        td
          = link_to '編集', edit_post_path(post), class: 'btn btn-primary mr-3'
```

続いて、詳細画面(app/views/posts/show.html.slim)にもリンクを追加します。

```ruby:app/views/posts/show.html.slim
h1 投稿の詳細

.nav.justify-content-end
  = link_to '一覧', posts_path, class: 'nav-link'
table.table.table-hover
  tbody
    tr
      th= Post.human_attribute_name(:id)
      td= @post.id
    tr
      th= Post.human_attribute_name(:content)
      td= simple_format(h(@post.content), {}, sanitize: false, wrapper_tag: "div")
    tr
      th= Post.human_attribute_name(:created_at)
      td= @post.created_at
    tr
      th= Post.human_attribute_name(:updated_at)
      td= @post.updated_at

= link_to '編集', edit_post_path, class: 'btn btn-primary mr-3'
```

##アクションの実装
編集機能は、編集画面を表示するeditアクションと、画面から送られてきたデータを使ってDBを更新するupdateアクションの2つが必要です。
まずは、app/views/posts/edit.html.slimを以下のように編集します。

```ruby:app/controllers/posts_controller.rb
def edit
  @post = Post.find(params[:id])
end

def update
  post = Post.find(params[:id])
  post.update!(post.params)
  redirect_to post_url, notice: "投稿内容を更新しました。"
end
```

editアクションでは、投稿データをフォーム画面で予め表示できるよう、URL内の投稿投稿IDをパラメータから受け取り、それを元にDBを検索して、編集対象のPostオブジェクトを取得し、インスタンス変数@postへ代入します。

updateアクションでは、同様に編集中のPostオブジェクトを取得し、update!メソッドによってpostパラメータの代入とDBへの保存の両方を行っています。このアクションはnewアクションとcreateアクションに似ています。

続いてビューを実装します。

```ruby:app/views/posts/edit.html.slim
h1 投稿の編集

.nav.justify-content-end
  = link_to '一覧', posts_path, class: 'nav-link'

= form_with model: @post, local: true do |f|
  .form-group
    = f.label :content
    = f.text_area :content, rows: 5, class: 'form-control', id: 'post_content'
  = f.submit nil, class: 'btn btn-primary'
```
![03CAC0F4-5709-40D9-9C76-D690744C4FE2_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/c935a9d0-9db5-2019-fd5e-ec26eca8f7a9.jpeg)

![76F4B515-DC73-49B3-BEFA-F6C52C50B4B4_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/d6e4f793-db4d-29d2-c802-475b99f409bb.jpeg)

##パーシャルを使った共通化
app/views/posts/new.html.slimファイルとapp/views/posts/edit.html.slimファイルを比べると入力フォーム部分が同じです。この同じ部分を共通化し、メンテナンスしやすくします。
共通化には、renderメソッドのパーシャルオプションを使います。
まず、パーシャルテンプレートとして、app/views/posts/_post.html.slimファイルを作ります。ファイル名の先頭にはアンダースコアをつけまが、呼び出す際はつけません。

app/views/posts/_post.html.slimに、app/views/posts/new.html.slimから、入力フォーム部分を切り取って貼り付けます。

```ruby:app/views/posts/_post.html.slim
= form_with model: post, local: true do |f|
  .form-group
    = f.label :content
    = f.text_area :content, rows: 5, class: 'form-control', id: 'post_content'
  = f.submit nil, class: 'btn btn-primary'
```

app/views/posts/new.html.slimには、以下のように書いてapp/views/posts/_form.html.slimを呼び出します。

```ruby:app/views/posts/new.html.slim
h1 つぶやきの新規投稿

.nav.justify-content-end
  = link_to '一覧', posts_path, class: 'nav-link'

= render partial: 'form', locals: {post: @post}
```

renderメソッドのlocalsオプションは、パーシャル内のローカル変数を設定します。locals: {post: @post}と記述すると、「インスタンス変数@postを、パーシャル内のローカル変数postとして渡す」という意味になります。これにより、ローカル変数postをパーシャル内から利用できるようになります。

app/views/posts/edit.html.slimファイルも同様に変更しておきます。

```ruby:app/views/posts/edit.html.slim
h1 投稿の編集

.nav.justify-content-end
  = link_to '一覧', posts_path, class: 'nav-link'

= render partial: 'form', locals: {post: @post}
```

これで、編集機能の実装は完了です！

#参考
[現場で使える Ruby on Rails 5速習実践ガイド](https://www.amazon.co.jp/gp/product/B07JHQ9B5T/ref=ppx_yo_dt_b_d_asin_title_o03?ie=UTF8&psc=1)