ユーザー登録機能の実装

①sorceryをインストール。
gem 'sorcery'
$ bundle exec rails g sorcery:install
class SorceryCore < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email, null: false
      t.string :crypted_password
      t.string :salt

      t.timestamps null: false
    end

    add_index :users, :email, unique: true
  end
end
$ bundle exec rails db:migrate


APIのルーティングを設定。
Rails.application.routes.draw do
  root to: 'home#index'
  namespace :api, format: 'json' do
    resources :tasks
    resources :users
  end
  get '*path', to: 'home#index'
end


③モデルを設定。
class User < ApplicationRecord
  authenticates_with_sorcery!

  has_many :tasks, dependent: :destroy

  validates :password, length: { minimum: 3 }, 
            if: -> { new_record? || changes[:crypted_password] }
  validates :password, confirmation: true,
            if: -> { new_record? || changes[:crypted_password] }
  validates :password_confirmation, presence: true,
            if: -> { new_record? || changes[:crypted_password] }

  validates :name, presence: true
  validates :email, uniqueness: true, presence: true
end


④コントローラーを設定。
class Api::UsersController < ApplicationController
  def create
    user = User.new(user_params)

    if user.save
      render json: user
    else
      render json: user.errors, status: :bad_request
    end
  end

  private

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation, :name)
  end
end


⑤vue-routerに登録画面のルーティングを設定してヘッダーにリンクを付ける。
import Vue from 'vue';
import Router from 'vue-router';
import store from '../store';

import TopIndex from '../pages/top/index';
import TaskIndex from '../pages/task/index';
import RegisterIndex from '../pages/register/index';

Vue.use(Router)

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: TopIndex,
      name: 'TopIndex',
    },
    {
      path: '/tasks',
      component: TaskIndex,
      name: 'TaskIndex',
      meta: { requiredAuth: true },
    },
    {
      path: '/register',
      component: RegisterIndex,
      name: 'RegisterIndex',
    },
  ]
})

export default router
<template>
  <header>
    <nav class="navbar navbar-expand navbar-dark bg-dark justify-content-between">
      <span class="navbar-brand mb-0 h1">タスク管理アプリ</span>
      <ul class="navbar-nav">
        <li class="nav-item active">
          <router-link
            :to="{ name: 'RegisterIndex' }"
            class="nav-link"
          >
            ユーザー登録
          </router-link>
        </li>
      </ul>
    </nav>
  </header>
</template>

<script>
export default {
  name: "TheHeader",
}
</script>

<style scoped>
</style>


⑥登録画面を実装。

app/javascript/pages/register/index.vue

<template>
  <div
    id="register-form"
    class="container w-50 text-center"
  >
    <div class="h3 mb-3">
      ユーザー登録
    </div>
    <div class="form-group text-left">
      <label for="name">ユーザー名</label>
      <input
        id="name"
        v-model="user.name"
        name="ユーザー名"
        type="text"
        placeholder="username"
        class="form-control"
      >
    </div>
    <div class="form-group text-left">
      <label for="email">メールアドレス</label>
      <input
        id="email"
        v-model="user.email"
        name="メールアドレス"
        type="email"
        placeholder="test@example.com"
        class="form-control"
      >
    </div>
    <div class="form-group text-left">
      <label for="password">パスワード</label>
      <input
        id="password"
        v-model="user.password"
        name="パスワード"
        type="password"
        placeholder="password"
        class="form-control"
      >
    </div>
    <div class="form-group text-left">
      <label for="password_confirmation">パスワード(確認)</label>
      <input
        id="password_confirmation"
        v-model="user.password_confirmation"
        name="パスワード(確認)"
        type="password"
        placeholder="password"
        class="form-control"
      >
    </div>
    <button
      type="submit"
      class="btn btn-primary"
      @click="register"
    >
      登録
    </button>
  </div>
</template>

<script>
export default {
  name: 'RegisterIndex',
  data() {
    return {
      user: {
        name: '',
        email: '',
        password: '',
        password_confirmation: ''
      }
    }
  },
  methods: {
    register() {
      this.$axios.post('users', this.user)
        .then(res => {
          this.$router.push('/login')
        })
        .catch(err => {
          console.log(err)
        })
    }
  }
}
</script>

<style scoped>
</style>