Todo作成機能を作る
前回のhttps://qiita.com/gabakugik/items/bd013dcc92fd64564139
続き
/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
def todo_params
params.require(:todo).permit(:title, :content)
end
end
/frontend/app/components/CreateTodoForm.tsx
"use client";
import { useState } from 'react';
import axios from 'axios';
import useSWR, { mutate } from 'swr';
// APIのエンドポイント
const API_URL = 'http://localhost:3000/todos';
// Fetcher関数
const fetcher = (url: string) => axios.get(url).then(res => res.data);
// Todoを作成するフォーム
const CreateTodoForm: React.FC = () => {
// フォームの入力値を管理するstate
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
// SWRを使ってデータをフェッチ
const { data, error } = useSWR(API_URL, fetcher);
// フォームの入力値を更新する関数
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
// APIを呼び出して、Todoを作成する
await axios.post(API_URL, {
todo: {
title,
content,
},
});
// Todoの作成に成功したら、フォームの入力値をリセットする
setTitle('');
setContent('');
// Todoの作成に成功したら画面を更新する(Todoを再取得するため)
mutate(API_URL);
} catch (error) {
console.error(error);
}
};
if (error) return <div>Failed to load todos</div>;
if (!data) return <div>Loading...</div>;
return (
<div className="space-y-6 w-3/4 max-w-lg py-10">
<form onSubmit={handleSubmit} className="space-y-6">
<label className="block text-xl font-bold text-gray-700">New Todo</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="タイトル"
className="block w-full py-2 pl-3 pr-4 text-base border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="本文"
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
/>
<button
type="submit"
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"
>
Create
</button>
</form>
</div>
);
};
export default CreateTodoForm;
/frontend/app/page.tsx
import Todos from '@/components/Todos';
import CreateTodoForm from '@/components/CreateTodoForm';
// トップページ
export default function Home() {
return (
<div className="flex flex-col justify-center items-center">
<Todos />
<CreateTodoForm />
</div>
);
}
これで完成。
localhost:3001でフォームがあり、追加できる。