【2.メモ登録編】Ruby on Rails + ReactでSNSアプリを作る
こんにちは、ミニマリストいずです。
Rail +ReactでSNS機能を持ったWEBアプリの作り方を紹介していく連続企画の第二弾です。
今回はメモの登録ができるようにしていきます。
初学者の方にもわかるようにまとめていきますが、不明点がありましたら以下から質問をいただければと思います。
作成するアプリの機能紹介(再掲)
サンプル動画(再掲)
作成する機能一覧(再掲)
動画でご覧いただくとお分かりになるかと思いますが、以下の機能を本アプリでは実装していきます。
- ユーザ管理機能
- 新規登録
- ログイン
- メモカテゴリ機能
- 作成
- 取得
- 動画内ではクレドと表現されている部分
- メモ機能
- 作成
- 一覧取得
- 詳細取得
- 動画内ではアクションメモと表現されている部分
- コメント機能
- 作成
- 取得
Webアプリの基本であるCRUDを実装しています。
どのアプリを作るにも参考になると思いますので、初学者の方にもおすすめのアプリになっています。
メモ登録機能(バックエンド編)
今回から各実行後の確認方法は省きますね。
もし確認方法を忘れてしまったら、前の記事に戻って確認してみてください。
もしそれでもわからなければ以下から無料質問してみてください。
メモのモデル・DB
以下のコマンドで、モデルを追加していきます。
rails g model memo
次に作成されたマイグレーションファイルを以下のように変更します。
1class CreateMemos < ActiveRecord::Migration[6.1]
2 def change
3 create_table :memos do |t|
4 t.string :content
5 t.references :category, index: true, foreign_key: true
6 t.timestamps
7 end
8 end
9end
変更できたらマイグレートを実行しましょう。
rails db:migrate
バリデーション・アソシエーションの設定
memo.rbにてバリデーションとアソシエーションを設定します。
1class Memo < ApplicationRecord
2 belongs_to :category
3 validates :category, :content, presence: true
4end
また、category.rbにて、アソシエーションも追加しておきます。
1class Category < ApplicationRecord
2 has_many :memos
3 validates :name, presence: :true
4end
5
ここまでコードが書けたら、rails cでコンソールを立ち上げて、データが登録できるかを確認してみてください。
カテゴリを先に登録していないとメモが登録できないので注意してください。
メモのコントローラー
以下のコマンドでメモのコントローラーを追加します。
rails g controller api::v1::memos
メモの登録ができるように、コントローラーのコードを変更します。
1class Api::V1::MemosController < ApplicationController
2 def create
3 memo = Memo.new(memo_params)
4 if memo.save
5 render json: memo, status: :created
6 else
7 render json: memo.errors, status: :unprocessable_entity
8 end
9 end
10
11 private
12
13 def memo_params
14 params.require(:memo).permit(:content, :category_id)
15 end
16end
17
カテゴリを取得できるようにコントローラーに追記
メモはカテゴリに紐づけて作成したいので、カテゴリを取得できるようにします。
1class Api::V1::CategoriesController < ApplicationController
2 def index
3 categories = Category.all
4 render json: categories
5 end
6
7 def create
8 category = Category.new(category_params)
9 if category.save
10 render json: category, status: :created
11 else
12 render json: category.errors, status: :unprocessable_entity
13 end
14 end
15
16 private
17
18 def category_params
19 params.require(:category).permit(:name)
20 end
21end
22
メモ作成、カテゴリ取得のルーティングを追加
config/routes.rbを以下のように書き換えます。
1Rails.application.routes.draw do
2 namespace :api do
3 namespace :v1 do
4 resources :categories, only: [:index, :create]
5 resources :memos, only: [:create]
6 end
7 end
8end
9
ここまでできたらcurlコマンドでメモが登録できるか、カテゴリが取得できるかを確認してみましょう。
メモのカテゴリが登録されていないと、メモは登録できない点に注意してください。
ここまででバックエンド編はおしまいです。不明点があったら以下から質問してみてください。
メモ登録機能(フロントエンド編)
必要なファイルを追加
src/component/pagesの下に、NewMemo.jsxを作成します。
メモ作成ページの表示確認
App.jsを以下のように変更し、メモ作成ページのルーティングを追加します。
1import { BrowserRouter, Routes, Route } from "react-router-dom";
2import NewCategory from "./component/page/NewCategory";
3import NewMemo from "./component/page/NewMemo";
4
5function App() {
6 return (
7 <BrowserRouter>
8 <Routes>
9 <Route path={`/category/new`} element={<NewCategory />} />
10 <Route path={`/memo/new`} element={<NewMemo />} />
11 </Routes>
12 </BrowserRouter>
13 );
14}
15
16export default App;
17
次に、NewMemo.jsxを表示確認ように変更します。
1export default function NewMemo() {
2 return (
3 "NewMemo"
4 );
5 }
yarn startコマンドでサーバーを起動し、ブラウザにNewMemoと表示されていたらOKです。
カテゴリを取得できるようにコーディング
メモを登録できるようにするために、メモに紐づけるためのカテゴリを取得できるようにします。
1import React, { useEffect, useState } from 'react';
2import {
3 Box,
4 Center,
5 Select,
6} from "@chakra-ui/react";
7import { useToast } from "@chakra-ui/react";
8import axios from 'axios';
9
10export default function NewMemo() {
11 const [ categories, setCategories] = useState([]);
12 const [ category_id, setCategoryId ] = useState('');
13 const toast = useToast();
14
15 useEffect(() => {
16 fetchGetCategory();
17 }, [])
18
19 async function fetchGetCategory() {
20 try {
21 const res = await axios.get("http://localhost:3010/api/v1/categories");
22
23 if (!res.status || (res.status < 200 && res.status >= 300)) {
24 throw new Error(`HTTP error! status: ${res.status}`);
25 }
26
27 setCategories(res.data);
28 }
29 catch (error) {
30 console.error('Error creating credos:', error);
31 toast({
32 title: 'カテゴリの取得に失敗しました。',
33 status: 'error',
34 isClosable: true,
35 });
36 }
37 }
38
39 return (
40 <Center>
41 <Box w={["100%", "90%", "80%", "70%", "60%"]} mt={["50px", "100px", "150px", "200px"]}>
42 <Select
43 onChange={(e) => setCategoryId(e.target.value)}
44 placeholder='カテゴリを選択して下さい。'
45 >
46 {categories.length > 0 && categories.map((item, index) => {
47 return <option value={item.id} key={index}>{item.name}</option>;
48 })}
49 </Select>
50 </Box>
51 </Center>
52 );
53 }
以下のように動作していたらOKです。
メモを登録できるようにコーディング
取得したカテゴリに紐づけてメモを登録できるようなコードに変更します。
1import React, { useEffect, useState } from 'react';
2import {
3 Box,
4 Input,
5 Button,
6 Center,
7 Select,
8} from "@chakra-ui/react";
9import { useToast } from "@chakra-ui/react";
10import axios from 'axios';
11
12export default function NewMemo() {
13 const [ categories, setCategories] = useState([]);
14 const [ category_id, setCategoryId ] = useState('');
15 const [ memo, setMemo ] = useState('');
16 const [isLoading, setIsLoading] = useState(false);
17 const toast = useToast();
18
19 useEffect(() => {
20 fetchGetCategory();
21 }, [])
22
23 async function fetchGetCategory() {
24 try {
25 const res = await axios.get("http://localhost:3010/api/v1/categories");
26
27 if (!res.status || (res.status < 200 && res.status >= 300)) {
28 throw new Error(`HTTP error! status: ${res.status}`);
29 }
30
31 setCategories(res.data);
32 }
33 catch (error) {
34 console.error('Error creating credos:', error);
35 toast({
36 title: 'カテゴリの取得に失敗しました。',
37 status: 'error',
38 isClosable: true,
39 });
40 }
41 }
42
43 async function fetchCreateMemo() {
44 setIsLoading(true);
45
46 try {
47 if (!category_id || !memo) {
48 toast({
49 title: 'カテゴリの選択とメモの入力をして下さい。',
50 status: 'error',
51 isClosable: true,
52 });
53
54 return;
55 }
56
57 const res = await axios.post("http://localhost:3010/api/v1/memos", {
58 memo: {
59 content: memo,
60 category_id
61 },
62 });
63
64 if (!res.status || (res.status < 200 && res.status >= 300)) {
65 throw new Error(`HTTP error! status: ${res.status}`);
66 }
67
68 toast({
69 title: 'メモを登録しました。',
70 status: 'success',
71 isClosable: true,
72 });
73 }
74 catch (error) {
75 console.error('Error creating credos:', error);
76 toast({
77 title: 'メモの登録に失敗しました。',
78 status: 'error',
79 isClosable: true,
80 });
81 }
82 finally {
83 setIsLoading(false);
84 setMemo('');
85 }
86 }
87
88 return (
89 <Center>
90 <Box w={["100%", "90%", "80%", "70%", "60%"]} mt={["50px", "100px", "150px", "200px"]}>
91 <Select
92 onChange={(e) => setCategoryId(e.target.value)}
93 placeholder='カテゴリを選択して下さい。'
94 >
95 {categories.length > 0 && categories.map((item, index) => {
96 return <option value={item.id} key={index}>{item.name}</option>;
97 })}
98 </Select>
99 <Input
100 value={memo}
101 onChange={(e) => setMemo(e.target.value)}
102 placeholder="追加したいメモを入力"
103 />
104 <Center>
105 <Button mt="6px" onClick={fetchCreateMemo} isLoading={isLoading} disabled={!memo || !category_id}>送信</Button>
106 </Center>
107 </Box>
108 </Center>
109 );
110 }
以下のような挙動になっていたらOKです。
コードの量が増えてきましたので、全てに対して解説することは控えます。
検索やChatGPT等に質問して知識理解を深めてみてほしいです。
もしわからないことがあったら無料質問を以下からしてみてください。
まとめ
SNSアプリを作成していくにあたり、RailsとReactを連携し、メモを登録できるようになりました。
次回はユーザを登録できるようにしていきます。ユーザが登録できるようになるとSNS感が一気に高まりますよね。