https://qiita.com/gabakugik/items/882d02d12c3a30beea29
の続きで最後の部分の削除を実装していきます。
/backend/app/controllers/todos_controller.rb
class TodosController < ApplicationController
def index
# 日付が新しい順に10件まで取得する
@todos = Todo.all.order(created_at: :desc).limit(10)
render json: @todos
end
def show
@todo = Todo.find(params[:id])
render json: @todo
end
def create
@todo = Todo.new(todo_params)
if @todo.save
render json: @todo, status: :created, location: @todo
else
render json: @todo.errors, status: :unprocessable_entity
end
end
def update
@todo = Todo.find(params[:id])
if @todo.update(todo_params)
render json: @todo
else
render json: @todo.errors, status: :unprocessable_entity
end
end
# DELETE /todos/:id
def destroy
@todo = Todo.find(params[:id])
@todo.destroy
end
def todo_params
params.require(:todo).permit(:title, :content)
end
end
/frontend/components/DeleteTodoButton.tsx
import { useRouter } from 'next/navigation';
import useSWR, { mutate } from 'swr';
import axios from 'axios';
type DeleteTodoButtonProps = {
id: number;
};
// Simple fetcher function if you need it for future use
const fetcher = (url: string) => axios.get(url).then(res => res.data);
// Todoを削除するボタン
const DeleteTodoButton = ({ id }: DeleteTodoButtonProps) => {
const router = useRouter();
// Todoを削除する関数
const handleDelete = async () => {
// 確認のダイアログを表示
if (!confirm('本当に削除しますか?')) {
return;
}
try {
// APIを呼び出して、Todoを削除する
await axios.delete(`http://localhost:3000/todos/${id}`);
// 削除に成功したら、SWRのキャッシュを無効化して再取得
mutate('/todos', async (todos: any) => {
// ローカルで楽観的に削除する
return todos ? todos.filter((todo: any) => todo.id !== id) : [];
}, false);
// トップページに遷移
router.push('/');
} catch (error) {
console.error(error);
}
};
return (
<button
onClick={handleDelete}
className="mt-3 ml-auto flex justify-center py-2 px-8 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Delete
</button>
);
};
export default DeleteTodoButton;
/frontend/app/todos/[id]/page.tsx
"use client";
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import useSWR from 'swr';
import Link from 'next/link';
import Todo from '@/components/Todo';
import { TodoType } from '@/types/Todo';
import axios from 'axios';
import DeleteTodoButton from '@/components/DeleteTodoButton';
// Fetcher function for SWR
const fetcher = (url: string) => axios.get(url).then(res => res.data);
// Todo詳細ページを表示するコンポーネント
const TodoDetail = ({ params }: { params: { id: string } }) => {
// ルーティング情報を取得する
const router = useRouter();
const { id } = params;
// SWRを使ってデータを取得する
const { data: todo, error } = useSWR<TodoType>(id ? `http://localhost:3000/todos/${id}` : null, fetcher);
// エラーが発生した場合の処理
if (error) return <div>Failed to load</div>;
// Todoを取得中の場合は「Loading...」を表示する
if (!todo) return <div>Loading...</div>;
return (
<div className="flex justify-center items-center">
<div className="flex flex-col space-y-6 w-3/4 max-w-lg pt-10">
<label className="block text-xl font-bold text-gray-700">Todo</label>
<Todo todo={todo} />
<div className="flex justify-end">
<Link
href={`/todos/${id}/edit`}
className="mt-auto font-medium text-blue-600 hover:bg-blue-300 focus:outline-none mr-12"
>
Edit
</Link>
<Link
href="/"
className="mt-auto font-medium text-blue-600 hover:bg-blue-300 focus:outline-none"
>
Back
</Link>
</div>
{/* 削除ボタンコンポーネントを追加 */}
<DeleteTodoButton id={todo.id} />
</div>
</div>
);
};
export default TodoDetail;
これで終わりです。
frontendが難しかったですが、できました。
ぜひ皆さんもやってみてください。