create

【3.ユーザ登録編】Ruby on Rails + ReactでSNSアプリを作る

pepe87
記事内に商品プロモーションを含む場合があります

こんにちは、ミニマリストいずです。

Rail +ReactでSNS機能を持ったWEBアプリの作り方を紹介していく連続企画の第3弾です。

今回はユーザ登録ができるようにしていきます。

初学者の方にもわかるようにまとめていきますが、不明点がありましたら以下から質問をいただければと思います。

作成するアプリの機能紹介(再掲)

サンプル動画(再掲)

作成する機能一覧(再掲)

動画でご覧いただくとお分かりになるかと思いますが、以下の機能を本アプリでは実装していきます。

作成する機能一覧
  • ユーザ管理機能
    • 新規登録
    • ログイン
  • メモカテゴリ機能
    • 作成
    • 取得
    • 動画内ではクレドと表現されている部分
  • メモ機能
    • 作成
    • 一覧取得
    • 詳細取得
    • 動画内ではアクションメモと表現されている部分
  • コメント機能
    • 作成
    • 取得

Webアプリの基本であるCRUDを実装しています。

どのアプリを作るにも参考になると思いますので、初学者の方にもおすすめのアプリになっています。

ユーザ登録機能(バックエンド編)

今回も各実行後の確認方法は省きますね。

もし確認方法を忘れてしまったら、前の記事に戻って確認してみてください。

あわせて読みたい
【1.カテゴリ新規登録編】Ruby on Rails + ReactでSNSアプリを作る
【1.カテゴリ新規登録編】Ruby on Rails + ReactでSNSアプリを作る

もしそれでもわからなければ以下から無料質問してみてください。

devise-token-auth、devise、devise-i18nのインストール

Gemfileに3つのGemを追記します。

追記できたらコマンドでインストールします。コマンドを実行する場所に注意してくださいね。

bundle install

railsをAPIモードで作る際には、devise-token-authを使用すると簡単にセキュアな認証システムを構築できます。

deviseをインストールしないと使えないので、deviseもインストールし、日本語対応するためにdevise-i18nもインストールしています。

それぞれのGemの説明は以下になります。

  1. Devise: DeviseはRuby on Railsアプリケーションでの認証やセッション管理を簡単に実装するためのGemです。Deviseを使用することで、ユーザーのサインアップ、サインイン、パスワードリセットなどの機能を簡単に実装することができます。カスタマイズ性が高く、様々な認証の方法やオプションを提供しています。
  2. Devise Token Auth: Devise Token AuthはDeviseをベースにしており、JSON Web Token(JWT)ベースの認証システムを提供するGemです。Devise Token Authを使用することで、Rails APIアプリケーションに対して簡単にトークンベースの認証を実装することができます。ユーザーがトークンを使用して認証し、APIエンドポイントにアクセスできるようになります。
  3. Devise-i18n: Devise-i18nはDeviseの国際化(i18n)用のGemです。Deviseは多言語対応をサポートしており、Devise-i18nを使用することで、異なる言語のユーザーインターフェース(UI)テキストを簡単に設定することができます。これにより、Deviseを使用するアプリケーションを異なる言語のユーザーに対してより使いやすくすることができます。

次に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

config.change_headers_on_each_requestfalseに設定することは、セキュリティ上のリスクを増やす可能性があります。これにより、トークンを含むヘッダーが毎回変更されずに同じまま維持されるため、悪意のある攻撃者がトークンをキャプチャして不正なアクセスを行う可能性が高まります。したがって、この設定を変更せずにデフォルトのままにすることが推奨されます。

代わりに、トークンのセキュリティを強化するために以下のような対策を検討することが重要です:

  1. HTTPSの使用: SSL/TLSを使用して通信を暗号化することで、トークンが傍受されることを防ぎます。HTTPSを使用することで、通信経路が安全になり、トークンが漏洩するリスクが低減します。
  2. トークンの有効期限の設定: トークンの有効期限を短く設定し、定期的に更新することで、トークンの有効性を制限します。これにより、トークンが漏洩した場合の被害を最小限に抑えることができます。
  3. セキュリティヘッダーの使用: Content Security Policy (CSP)、X-Content-Type-Options、X-Frame-Optionsなどのセキュリティヘッダーを適切に設定することで、XSS(Cross-Site Scripting)やクリックジャッキングなどの攻撃から保護することができます。
  4. 不正アクセスの監視と検知: サーバーログやセキュリティモニタリングツールを使用して、不正なアクセスを監視し、必要に応じて対策を講じることが重要です。

これらの対策を組み合わせることで、トークンのセキュリティを強化し、システム全体のセキュリティを向上させることができます。

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の方を使っています。

rails db:migraterails db:migrate:resetは、どちらもRailsアプリケーション内のデータベースに対するマイグレーションを実行するコマンドですが、異なる動作をします。

  1. rails db:migrate:
    • このコマンドは、まだ実行されていないマイグレーションファイルを順番に実行し、データベースのスキーマを最新の状態に更新します。つまり、新しいマイグレーションファイルが存在し、まだ適用されていない場合にのみ、新しい変更がデータベースに適用されます。
  2. rails db:migrate:reset:
    • このコマンドは、データベースを状態を初期状態に戻すために使用されます。具体的には、以下の手順を実行します。
      • データベースのリセット (rails db:drop)
      • データベースの再作成 (rails db:create)
      • すべてのマイグレーションを実行し直す (rails db:migrate)
    つまり、データベース内のすべてのテーブルが削除され、最初の状態に戻され、その後すべてのマイグレーションが再度適用されます。データベース内のすべてのデータも失われることに注意してください。

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 }

現時点では新規登録できたかがWebブラウザからは確認できないので、console.log()を使って、レスポンスに含まれるトークン情報を表示するようにしています。

Webブラウザで右クリックをすると、以下のように「検証」というものが出てきます。

クリックすると以下のようなconsole.log()の括弧の中身を表示してくれる画面が表示されます。

挙動確認の際にどのように表示されているかも一緒に確認し、console.log()の使い方も把握しておきましょう。

以下のような挙動になっていたらOKです。

ユーザ登録機能はいかがでしたか?

途中でもお伝えしましたが、今回はdevise-token-authのライブラリを使っているので、一部どうやってコードが動いているのかがわかなくなったと思います。

ただ、中身がわからないからと言ってライブラリを使わないというのは現実的ではありません。

ライブラリを使うと実装が高速になりますので、中身がわからなくても動いていればOK。

ライブラリの公式の文書を読み、どんな使い方をすればいいのかを理解すれば高速に実装、開発ができるようになります。

ライブラリの読み込み方や今まで紹介してきたコードについて聞いてみたいことがある!という方は無料質問もできるので以下を確認してみてください。

まとめ

SNSアプリを作成していくにあたり、RailsとReactを連携し、ユーザ登録できるようになりました。

次回はログインできるようにしていきます。

次へ進む
【4.ログイン編】Ruby on Rails + ReactでSNSアプリを作る
【4.ログイン編】Ruby on Rails + ReactでSNSアプリを作る
ABOUT ME
いず
いず
ライフコーチ・ミニマリスト・IT系
Hard Funな時間を増やすためにミニマリストに。ライフコーチ、プログラミングのサービス開発・メンターをやりながら、ブログを運営。ミニマリストのおすすめアイテムや、考え方を発信していきます。
Recommend
こちらの記事もどうぞ
記事URLをコピーしました