学習ログ削除機能作成
今回は、学習ログ関連機能の締めくくりとして削除機能を実装します。
実装
ルーティング
PostsController の各アクションへのルーティングについては resources で指定していました。
許可するアクションとして destroy
も追加してあげましょう。
config/routes.rb
resources :posts, only: [ :index, :new, :create, :show, :destroy] # 修正
Controller (#destroy)
次に Controller にアクションを追加します。
app/controllers/posts_controller.rb
def destroy
@post = Post.find_by(id: params[:id])
if @post.user == current_user
@post.destroy
flash[:notice] = '投稿が削除されました'
end
redirect_to posts_path
end
毎度おなじみですが、private よりも上に追加することに注意しましょう。
View
最後に、view ファイルを編集します。
削除機能については個別の view は用意せず、投稿の詳細ページの中に削除ボタンを設置します。
ただし、他の人の投稿は削除できないよう、Post のユーザーとログインユーザーが一致する場合にのみ削除ボタンを表示させます。
以上の要件を満たした view ファイルが以下の通りです。
部分的に追加しています。
app/views/posts/show.html.erb
<div class="space-y-6 w-3/4 max-w-lg">
<label class="block text-xl font-bold text-gray-700">学習ログ詳細</label>
<div class="items-center justify-center">
<div tabindex="0" aria-label="card 1" class="focus:outline-none mb-7 bg-white p-6 shadow rounded">
<div class="flex items-center border-b border-gray-200 pb-6">
<div class="flex items-start justify-between w-full">
<div class="pl-3">
<p class="focus:outline-none text-lg font-medium leading-5 text-gray-800"><%= link_to @post.title, post_path(@post) %></p>
<p class="focus:outline-none text-sm leading-normal pt-2 text-gray-500">by <%= @post.user.nickname %></p>
</div>
<%# ここから追加 %>
<% if user_signed_in? %>
<% if @post.user_id == current_user.id %>
<%= button_to "削除", post_path(@post), method: :delete, class: "text-sm bg-transparent hover:bg-blue-500 text-blue-700 hover:text-white py-1 px-3 border border-blue-500 hover:border-transparent rounded" %>
<% end %>
<% end %>
</div>
</div>
<div class="px-2">
<p class="focus:outline-none text-sm leading-5 py-4 text-gray-600"><%= @post.content %></p>
</div>
</div>
</div>
</div>
devise のヘルパーメソッド user_signed_in?
を使っています。
これはログインしていれば trueを返すヘルパーメソッドです。
これがないと、ログインしていない時には current_user が nil になるため、current_user.id
のところで NoMethodError
を吐いてしまうので注意してください。
<% if user_signed_in? %>
がない場合のエラー
動作確認
それでは動作確認していきましょう。
削除機能は、投稿したユーザーかどうかで挙動が変わるため、両方のパターンで動作確認しておきます。
投稿したユーザーの場合
まずは投稿したユーザー本人の場合です。
適当なユーザーでログインし、1件学習ログを投稿した後にその投稿の詳細画面を開きます。
:id
には投稿した Post の ID を当てはめてください)
また、削除ボタンを押すとフラッシュメッセージ表示されると共に投稿が削除されつつ、
学習ログの一覧からも消えていることを確認してください。
投稿したユーザー以外の場合
次は投稿したユーザー以外の表示です。
別なユーザーを作ってログイン、またはログアウトし、学習ログ一覧から任意の投稿の詳細画面にアクセスしてください。
削除ボタンが表示されていなければ OK です。
テスト
それでは、削除機能に関するテストを追加しましょう。
先ほど動作確認した内容を System Spec に追加します。
...
describe 'ログ削除機能の検証' do
context '投稿したユーザーでログインしている場合' do
before do
sign_in @user
visit "/posts/#{@post.id}"
end
it '削除ボタンを表示する' do
expect(page).to have_button('削除')
end
it '削除ボタンをクリックすると削除できる' do
expect do
click_button '削除'
end.to change(Post, :count).by(-1) # 削除ボタンをクリックするとPostが1つ減る
# リダイレクト後の画面確認
expect(current_path).to eq('/posts')
expect(page).to have_content('投稿が削除されました') # フラッシュメッセージを表示
expect(page).not_to have_link("/posts/#{@post.id}") # 削除した投稿(の詳細ページへのリンク)が存在しない
end
end
context '投稿したユーザーでログインしていない場合' do
it '削除ボタンを表示しない' do
visit "/posts/#{@post.id}"
expect(page).not_to have_button('削除')
end
it '直接リクエストを投げても削除されない' do
visit "/posts/#{@post.id}"
expect do
delete post_path(@post) # 投稿データを削除するリクエストを送る
end.not_to change(Post, :count)
end
end
end
end
最後にすべてのテストを実行し、通ることを確認します。
$ bin/rspec
...
Finished in 13.55 seconds (files took 0.41183 seconds to load)
62 examples, 0 failures
変更をコミット
ここまでの変更をコミットしておきましょう。
$ git add .
$ git commit -m "学習ログ削除機能を作成"
$ git push
宿題
user_signed_in?
今回、詳細ページで表示の切り替えをするために devise のヘルパーメソッドである user_signed_in?
を使いました。
Controller, View のどちらでも使用できる便利なメソッドですので、改めて使い方はおさえておきましょう。