【Ruby on Rails】投稿したユーザーのみが編集できるようにする

# 目標

- URLのベタ打ちでの他ユーザーの編集を防ぐ
- view画面にそもそも表示させない


# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# 前提

※　▶◯◯　を選択すると、説明等が出てきますので、
　　よくわからない場合の参考にしていただければと思います。

- [deviseでログイン環境構築](https://qiita.com/japwork/items/275110b810965fbdf72f)
- [ログインユーザーのみができる投稿機能](https://qiita.com/japwork/items/8dfb52121036791ac4fb)
- [投稿の編集機能（更新、削除）](https://qiita.com/japwork/items/e258ccbbe4f48ea5a3b5)

# 考え方
基本的には、
①if文でcurrent_userなどで絞るか、
②current_userに紐づくモデルを抽出するかで
投稿したユーザーのみが編集可能。
※viewでは前者を、controllerでは後者で実装。


# controllerの編集
前提の状態での記述

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

	def update
    @post = Post.find(params[:id])
		if @post.update(post_params)
      redirect_to new_post_path
    else
      render :edit
    end
	end

	def destroy
		@posts = Post.all
		@post = Post.find(params[:id])
		@post.destroy
	end
```


このままではURLをベタ打ちすると編集、削除が可能に。
そこで下記のように記述。

```rb:app/controllers/posts_controller.rb
  def edit
    @post = Post.find(params[:id])
    unless @post.user == current_user
      redirect_to  new_post_path
    end
  end

  def update
    @post = Post.find(params[:id])
    if @post.user != current_user
      redirect_to  new_post_path
    else
      if @post.update(post_params)
        redirect_to new_post_path
      else
        render :edit
      end
    end
  end

  def destroy
    @posts = Post.all
    @post = Post.find(params[:id])
    if @post.user != current_user
      redirect_to  new_post_path
    else
      @post.destroy
    end
  end
```
<details><summary>補足</summary>
unless 条件　=>　条件がfalseの場合を定義。</details>

ただしこれでは記述が多くなり、修正する場合に手間が必要。
そこでbefore_actionを活用。

```rb:app/controllers/posts_controller.rb

before_action :ensure_user, only: [:edit, :update, :destroy]

...
	
  def edit
  end

  def update
    if @post.update(post_params)
      redirect_to new_post_path
    else
      render :edit
    end
  end

  def destroy
    @post.destroy
    redirect_to new_post_path
  end

  private
  def ensure_user
    @posts = current_user.posts
    @post = @posts.find_by(id: params[:id])
    redirect_to new_post_path unless @post
  end

...

```

<details><summary>補足</summary>
before_actionを活用することにより、アクションが読み込まれる前に行う動作を指定することができる。
定義はストロングパラメーターで行い、current_userでない場合はreditrct_toを定義。</details>

# viewsの編集
URLベタ打ち以前にそもそもユーザー誤認を防ぐために画面で表示をしない方が望ましい。

```erb:app/views/posts/new.html.erb
<% @posts.each do |post| %>
	<tr>
		<td><%= post.user.name %></td>
		<td><%= post.title %></td>
		<td><%= post.body %></td>
		<td><%= link_to "詳細", post_path(post) %></td>
		<td><%= link_to "編集", edit_post_path(post) %></td>
		<td><%= link_to "削除", post_path(post), method: :delete %></td>
	</tr>
<% end %>
```

この部分を修正。

```erb:app/views/posts/new.html.erb
<% @posts.each do |post| %>
  <tr>
    <td><%= post.user.name %></td>
    <td><%= post.title %></td>
    <td><%= post.body %></td>
    <td><%= link_to "詳細", post_path(post) %></td>
    <% if post.user == current_user %>
      <td><%= link_to "編集", edit_post_path(post) %></td>
      <td><%= link_to "削除", post_path(post), method: :delete %></td>
    <% else %>
      <td></td>
      <td></td>
    <% end %>
  </tr>
<% end %>
```

# 結論
 controllerとviewを編集することにより、他ユーザーの編集を防ぐことが可能。