【3.ユーザ登録編】Ruby on Rails + ReactでSNSアプリを作る
こんにちは、ミニマリストいずです。
Rail +ReactでSNS機能を持ったWEBアプリの作り方を紹介していく連続企画の第3弾です。
今回はユーザ登録ができるようにしていきます。
初学者の方にもわかるようにまとめていきますが、不明点がありましたら以下から質問をいただければと思います。
作成するアプリの機能紹介(再掲)
サンプル動画(再掲)
作成する機能一覧(再掲)
動画でご覧いただくとお分かりになるかと思いますが、以下の機能を本アプリでは実装していきます。
- ユーザ管理機能
- 新規登録
- ログイン
- メモカテゴリ機能
- 作成
- 取得
- 動画内ではクレドと表現されている部分
- メモ機能
- 作成
- 一覧取得
- 詳細取得
- 動画内ではアクションメモと表現されている部分
- コメント機能
- 作成
- 取得
Webアプリの基本であるCRUDを実装しています。
どのアプリを作るにも参考になると思いますので、初学者の方にもおすすめのアプリになっています。
ユーザ登録機能(バックエンド編)
今回も各実行後の確認方法は省きますね。
もし確認方法を忘れてしまったら、前の記事に戻って確認してみてください。
もしそれでもわからなければ以下から無料質問してみてください。
devise-token-auth、devise、devise-i18nのインストール
Gemfileに3つのGemを追記します。
追記できたらコマンドでインストールします。コマンドを実行する場所に注意してくださいね。
bundle install
次にdeviseを有効化するために以下のコマンドを実行します。
rails g devise:install
devise-token-authも同様に有効化します。Userは自由に決められるモデル名となっていますが、Userにするのが一般的です。
rails g devise_token_auth:install User auth
devise-token-authのトークン有効期限を変更
devise-token-authはトークンを用いて認証を行うのですが、デフォルトではセキュリティの観点からトークンが通信するたびに変更されるようになっています。
トークン管理が煩雑になりますので、変更していきます。
以下がコメントアウトされていますので、コメントアウトを解除し、falseにします。
config.change_headers_on_each_request = true
deviseのメッセージを日本語化
デフォルトでdeviseのメッセージは英語になっておりますので、コマンドで日本語ファイルを作成します。
rails g devise:i18n:locale ja
以下のdevise.views.ja.ymlファイルが生成されていたらOKです。
また、タイムゾーンとデフォルト言語を日本語にするため、config/application.rbを以下のように変更していきます。
1require_relative "boot"
2
3require "rails"
4# Pick the frameworks you want:
5require "active_model/railtie"
6require "active_job/railtie"
7require "active_record/railtie"
8require "active_storage/engine"
9require "action_controller/railtie"
10require "action_mailer/railtie"
11require "action_mailbox/engine"
12require "action_text/engine"
13require "action_view/railtie"
14require "action_cable/engine"
15# require "sprockets/railtie"
16require "rails/test_unit/railtie"
17
18Bundler.require(*Rails.groups)
19
20module TodoApi
21 class Application < Rails::Application
22 config.load_defaults 6.1
23 config.time_zone = 'Tokyo'
24 config.i18n.default_locale = :ja
25 config.api_only = true
26 end
27end
28
新規登録コントローラーの設定
先程行ったトークンを通信のたびに更新する設定を無効にすると、レスポンスにはaccess-tokenとclientが含まれなくなり、トークン情報を発行するコードを追記してあげる必要があります。
そのため、コントローラーのファイルを用意し、機能追加をしていきます。
api/v1/auth/registrations_controller.rbとなるように、フォルダ、ファイルを追加します。
そして、以下のように記述します。
1class Api::V1::Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController
2 def render_create_success
3 auth_token = @resource.create_new_auth_token
4 render json: {
5 data: resource_data(resource_json: @resource.token_validation_response),
6 access_token: auth_token['access-token'],
7 client: auth_token['client'],
8 uid: auth_token['uid'],
9 }
10 end
11
12 def sign_up_params
13 params.permit(:name, :email, :password, :password_confirmation)
14 end
15end
新規登録ルーティングの設定
デフォルトでは追加したコントローラーを使ってもらえないので、ルーティングを変更します。
1Rails.application.routes.draw do
2 namespace :api do
3 namespace :v1 do
4 mount_devise_token_auth_for 'User', at: 'auth', controllers: {
5 registrations: 'api/v1/auth/registrations',
6 }
7
8 resources :categories, only: [:index, :create]
9 resources :memos, only: [:create]
10 end
11 end
12end
13
userのアソシエーション設定
userテーブルとcategory、memoテーブルを紐づけるためにはuser_idカラムがそれぞれ必要ですので、マイグレーションファイルを生成していきます。
rails generate migration AddUserIdToMemos user:references
rails generate migration AddUserIdToCategories user:references
ここでマイグレーションをしていきますが、今までとコマンドが違うのでご注意ください。
rails db:migrate:reset
user_idは今まで存在しなかったカラムなので、これまでDBに保存してきたmemoやcategoryには当然user_idは保存されていません。
ですが、refences型を指定すると、デフォルトでnull:false制約がつきますので、user_idが登録されていないデータが存在するとエラーになってしまいます。
そのため、今回は:resetの方を使っています。
devise-token-authの有効化のコマンド実行時にモデルファイルは作成されているのですが、アソシエーションは自動では追記されません。
そのため、userテーブルにまつわるアソシエーションを各種設定していきます。
1# frozen_string_literal: true
2
3class User < ActiveRecord::Base
4 # Include default devise modules. Others available are:
5 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
6 devise :database_authenticatable, :registerable,
7 :recoverable, :rememberable, :validatable
8 include DeviseTokenAuth::Concerns::User
9
10 has_many :categories
11 has_many :memos
12end
13
1class Memo < ApplicationRecord
2 belongs_to :category
3 belongs_to :user
4 validates :category, :content, presence: true
5end
6
1class Category < ApplicationRecord
2 has_many :memos
3 belongs_to :user
4 validates :name, presence: :true
5end
6
ライブラリを使っているので、何と今回はバックエンドはこれだけです。
でも言われるがままに設定してきただけだし、本当に理解できているのかな?と不安になるのがデメリット。
写しているだけになっていないか?と不安になったら是非無料質問してみてください。
ユーザ登録機能(フロントエンド編)
まずはユーザ登録用のjsxファイルを新しく用意します。
次に以下のようなコードを追記します。
1import React, { useState } from 'react';
2import {
3 Box,
4 Input,
5 Button,
6 Center,
7} from "@chakra-ui/react";
8import { useToast } from "@chakra-ui/react";
9import axios from 'axios';
10
11export default function UserRegist() {
12 const [ name, setName] = useState('');
13 const [ email, setEmail ] = useState('');
14 const [ password, setPassword ] = useState('');
15 const [ password_confirmation, setPasswordCofirmaiton ] = useState('');
16 const [isLoading, setIsLoading] = useState(false);
17 const toast = useToast();
18
19 async function fetchCreateUser() {
20 setIsLoading(true);
21
22 try {
23 if (!name || !email || !password || !password_confirmation) {
24 toast({
25 title: '名前、メールアドレス、パスワードを入力をして下さい。',
26 status: 'error',
27 isClosable: true,
28 });
29
30 return;
31 }
32
33 const res = await axios.post("http://localhost:3010/api/v1/auth", {
34 name, email, password, password_confirmation
35 });
36
37 if (!res.status || (res.status < 200 && res.status >= 300)) {
38 throw new Error(`HTTP error! status: ${res.status}`);
39 }
40
41 localStorage.setItem('access-token', res.data['access_token']);
42 localStorage.setItem('client', res.data['client']);
43 localStorage.setItem('uid', res.data['uid']);
44
45 console.log(localStorage.getItem('access-token'));
46 console.log(localStorage.getItem('client'));
47 console.log(localStorage.getItem('uid'));
48
49 toast({
50 title: '新規登録しました。',
51 status: 'success',
52 isClosable: true,
53 });
54 }
55 catch (error) {
56 console.error('Error creating credos:', error);
57 toast({
58 title: '新規登録に失敗しました。',
59 status: 'error',
60 isClosable: true,
61 });
62 }
63 finally {
64 setIsLoading(false);
65 setName('');
66 setEmail('');
67 setPassword('');
68 setPasswordCofirmaiton('');
69 }
70 }
71
72 return (
73 <Center>
74 <Box w={["100%", "90%", "80%", "70%", "60%"]} mt={["50px", "100px", "150px", "200px"]}>
75 <Input
76 value={name}
77 onChange={(e) => setName(e.target.value)}
78 placeholder="名前を入力"
79 />
80 <Input
81 mt="6px"
82 value={email}
83 onChange={(e) => setEmail(e.target.value)}
84 placeholder="Eメールを入力"
85 />
86 <Input
87 mt="6px"
88 type='password'
89 value={password}
90 onChange={(e) => setPassword(e.target.value)}
91 placeholder="パスワード"
92 />
93 <Input
94 mt="6px"
95 type='password'
96 value={password_confirmation}
97 onChange={(e) => setPasswordCofirmaiton(e.target.value)}
98 placeholder="パスワード(確認用)"
99 />
100 <Center>
101 <Button mt="6px" onClick={fetchCreateUser} isLoading={isLoading} disabled={!name || !email || !password || !password_confirmation}>送信</Button>
102 </Center>
103 </Box>
104 </Center>
105 );
106 }
以下のような挙動になっていたらOKです。
ユーザ登録機能はいかがでしたか?
途中でもお伝えしましたが、今回はdevise-token-authのライブラリを使っているので、一部どうやってコードが動いているのかがわかなくなったと思います。
ただ、中身がわからないからと言ってライブラリを使わないというのは現実的ではありません。
ライブラリを使うと実装が高速になりますので、中身がわからなくても動いていればOK。
ライブラリの公式の文書を読み、どんな使い方をすればいいのかを理解すれば高速に実装、開発ができるようになります。
ライブラリの読み込み方や今まで紹介してきたコードについて聞いてみたいことがある!という方は無料質問もできるので以下を確認してみてください。
まとめ
SNSアプリを作成していくにあたり、RailsとReactを連携し、ユーザ登録できるようになりました。
次回はログインできるようにしていきます。