目標
- URLのベタ打ちでの他ユーザーの編集を防ぐ
- view画面にそもそも表示させない
開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina
前提
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。
考え方
基本的には、
①if文でcurrent_userなどで絞るか、
②current_userに紐づくモデルを抽出するかで
投稿したユーザーのみが編集可能。
※viewでは前者を、controllerでは後者で実装。
controllerの編集
前提の状態での記述
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をベタ打ちすると編集、削除が可能に。
そこで下記のように記述。
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
補足
unless 条件 => 条件がfalseの場合を定義。ただしこれでは記述が多くなり、修正する場合に手間が必要。
そこでbefore_actionを活用。
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
...
補足
before_actionを活用することにより、アクションが読み込まれる前に行う動作を指定することができる。 定義はストロングパラメーターで行い、current_userでない場合はreditrct_toを定義。viewsの編集
URLベタ打ち以前にそもそもユーザー誤認を防ぐために画面で表示をしない方が望ましい。
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 %>
この部分を修正。
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を編集することにより、他ユーザーの編集を防ぐことが可能。