#編集機能の実装
編集機能では、既に登録された投稿の属性の値を変更してDBに保存します。
一覧画面の投稿情報ごとに「編集」リンクが表示され、そのリンクから編集画面へ遷移することにします。
また、詳細画面にも編集ボタンを設けるようにします。
##編集リンクの設置
まずは一覧画面(app/views/posts/index.html.slim)に編集画面へのリンクを設置します。
編集画面はedit_post_pathというヘルパーメソッドにより、post/[投稿ID]/editというURLを生成できます。
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)にもリンクを追加します。
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を以下のように編集します。
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アクションに似ています。
続いてビューを実装します。
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'
##パーシャルを使った共通化
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から、入力フォーム部分を切り取って貼り付けます。
= 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を呼び出します。
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ファイルも同様に変更しておきます。
h1 投稿の編集
.nav.justify-content-end
= link_to '一覧', posts_path, class: 'nav-link'
= render partial: 'form', locals: {post: @post}
これで、編集機能の実装は完了です!