0
0

Next.js×Railsでdelete画面を作る。

Last updated at Posted at 2024-08-27

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が難しかったですが、できました。
ぜひ皆さんもやってみてください。

frontendのフォルダ構成
スクリーンショット 2024-08-27 193558.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0