【Vue.js】タスク詳細ページをモーダルで表示する

はじめに

タスクの詳細ページをモーダルで表示する。

前提

前提として下記のtaskテーブルがあります。

class Task < ApplicationRecord
  validates :title, presence: true
  validates :description, length: { maximum: 1000 }
end
  create_table "tasks", force: :cascade do |t|
    t.string "title", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.text "description"
  end

詳細ページのコンポーネントを作成

まずは詳細ページのコンポーネントを作成します。

$ mkdir app/javascript/pages/task

$ mkdir app/javascript/pages/task/components

$ touch app/javascript/pages/task/components/TaskDetailModal.vue

モーダルはbootstrapのモーダルをベースにします。

<template>
  <div :id="'task-detail-modal-' + task.id">
    <div class="modal" @click.self="handleCloseModal">//  :1
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">{{ task.title }}</h5>
            <button type="button" class="close" @click="handleCloseModal">// :2
              <span>&times;</span>
            </button>
          </div>
          <div class="modal-body" v-if="task.description">
            <p>{{ task.description }}</p>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="handleCloseModal">閉じる</button>//  :2
          </div>
        </div>
      </div>
    </div>
    <div class="modal-backdrop show"></div>
  </div>
</template>

<script>
export default {
  name: "TaskDetailModal",
  props: {     // :3
    task: {
      title: {
        type: String,   
        required: true   
      },
      description: {
        type: String,
        required: true
      }
    }
  },
  methods: {
    handleCloseModal() {
      this.$emit('close-modal')    // :4
    }
  }
}
</script>

<style scoped>
 .modal {
  display: block;    // モーダルの表示・非表示をvueでコントールするので最初から表示状態にする
}
</style>

:1

<div class="modal" @click.self="handleCloseModal"> 

モーダル以外の部分をクリックしたときにもモーダルを非表示にします。

:2

<button type="button" class="close" @click="handleCloseModal"> 

<button type="button" class="btn btn-secondary" @click="handleCloseModal">閉じる</button> 

モーダルのxボタンと閉じるボタンをクリックした時にモーダルを非表示にします。

:3

  props: {  
    task: {
      title: {
        type: String,   //  データのタイプを指定
        required: true    // 必須かどうか
      },
      description: {
        type: String,
        required: true
      }
    }

propsを使って親コンポーネントからデータを受け取ります。

:4

  methods: {
    handleCloseModal() {
      this.$emit('close-modal')  
    }
  }

$emitメソッドを使って親コンポーネントのイベントを発火します。

詳細ページのモーダルを呼び出す

<template>
  <div>
    <div class="d-flex">
      <div class="col-4 bg-light rounded shadow m-3 p-3">
        <div class="h4">TODO</div>
        <div v-for="task in tasks" 
            :key="task.id" 
            :id="'task-' + task.id"
            class="bg-white border shadow-sm rounded my-2 p-4"
            @click="handleShowTaskDetailModal(task)">// :1
          <span>{{ task.title }}</span>
        </div>
      </div>
    </div>
    <div class="text-center">
      <router-link :to="{ name: 'TopIndex' }" class="btn btn-dark mt-5">戻る</router-link>
    </div>
    <transition name="fade">    // モーダルの表示非表示にtrannsitionをつける。
      <TaskDetailModal v-if="isVisibleTaskDetailModal" @close-modal="handleCloseTaskDetailModal" :task="taskDetail" /> 
         //  :2
    </transition>
  </div>
</template>

<script>
import TaskDetailModal from './components/TaskDetailModal' 
//  詳細ページのコンポーネントをインポート

export default {
  components: {
    TaskDetailModal
  },
  name: "TaskIndex",
  data() {
    return {
      tasks: [],
      taskDetail: {}, 
      isVisibleTaskDetailModal: false  //  モーダルをデフォルトで非表示に設定
    }
  },

  created() {
    this.fetchTasks();
  },

  methods: {
    fetchTasks() {
      this.$axios.get("tasks")
        .then(res => this.tasks = res.data)
        .catch(err => console.log(err.status));
    },
    handleCloseTaskDetailModal() {    //  子コンポーネントから呼び出しているメソッド
      this.isVisibleTaskDetailModal = false;   //  モーダルを非表示にする
      this.taskDetail = {};  //  引数のタスクを空にする
    },
    handleShowTaskDetailModal(task) {
      this.isVisibleTaskDetailModal = true;   // モーダルを表示
      this.taskDetail = task;   //  引数のタスクを代入
    }
  }
}
</script>

//  :4
<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}

.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>

:1

@click="handleShowTaskDetailModal(task)">  

クリックされたtaskのデータを引数で渡します。

:2

<TaskDetailModal v-if="isVisibleTaskDetailModal" @close-modal="handleCloseTaskDetailModal" :task="taskDetail" /> 

v-ifを使ってisVisibleTaskDetailModalがtrueのときは表示、falseのときは非表示にします。

先程の子コンポーネントから呼んでるイベントが@close-modal

(v-bind):task="taskDetail"でtaskのデータを子コンポーネントに渡しています。

そして子コンポーネントpropsで受け取っています。

:3

下記4つのクラスはenter/leaveトランジションを適用するための特殊なクラスです。

fadeの部分はname属性です。

name属性(fadeなど) + 特殊クラス(-enter-activeなど)
<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}

.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>

今回だとモーダルが表示されるトランジションの開始から終了まで。

今回だとモーダルが非表示されるトランジションの開始から終了まで。

完成画面

f:id:study-output:20210622060148p:plain

f:id:study-output:20210622060202p:plain

【Vue.js】RailsApiからjson形式のデータを取得する

はじめに

Vue.jsでRailsApiからjson形式のデータを取得する方法について。

前提

下記のようなtaskモデルがあります。

class CreateTasks < ActiveRecord::Migration[6.0]
  def change
    create_table :tasks do |t|
      t.string :title, null: false

      t.timestamps
    end
  end
end
class Task < ApplicationRecord
  validates :title, presence: true
end

コントローラを作成

まずはコントローラを作成します。

$ bundle exec rails g controller Api::Tasks index show create update destroy --skip-routes
class Api::TasksController < ApplicationController
  before_action :set_task, only: %i[show update destroy]

  def index
    @tasks = Task.all
    render json: @tasks
  end

  def show
    render json: @task
  end

  def create
    @task = Task.new(task_params)

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

  def update
    if @task.update(task_params)
      render json: @task
    else
      render json: @task.errors, status: :bad_request
    end
  end

  def destroy
    @task.destroy!
    render json: @task
  end

  private

  def set_task
    @task = Task.find(params[:id])
  end

  def task_params
    params.require(:task).permit(:title)
  end
end

ルーティングを追加

続いてルーティングを追加します。

Rails.application.routes.draw do
  root to: 'home#index'

  namespace :api do   #  追加
    resources :tasks
  end

  get '*path', to: 'home#index'
end

CSRF対策を無効化

railsに標準で搭載されているCSRF対策を無効化します。

これがあるとpostリクエストができなくなるということと、APIにおいてはこの機能は必要がないため。

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end

curlコマンドでタスクを追加

下記コマンドでタスクを3つ追加します。

curlコマンドを使うと、ローカルのターミナルからhttpリクエストを送ることができます。

$ curl -X POST -H "Content-Type: application/json" -d '{"title":"Rubyのサンプルコードを書く"}' localhost:3000/api/tasks

$ curl -X POST -H "Content-Type: application/json" -d '{"title":"Dockerを勉強する"}' localhost:3000/api/tasks

$ curl -X POST -H "Content-Type: application/json" -d '{"title":"JavaScriptのfor文を理解する"}' localhost:3000/api/tasks

axiosの設定

axiosはAPI通信をするためのhttpクライアントです。

まずはこれをインストールします。

$ yarn add axios

下記コマンドでaxiosの設定ファイルを作成します。

$ mkdir app/javascript/plugins

$ touch app/javascript/plugins/axios.js

axiosのインポートと、baseURLの設定をします。

import axios from 'axios'

const instance = axios.create({
  baseURL: 'api'
})

export default instance

先程作ったaxiosインスタンスのインポートと、他のvueファイルでthis.$axios.get.....のようにaxiosを使えるようにするための定義をします。

import Vue from 'vue'
import App from '../app.vue'
import router from '../router'
import axios from '../plugins/axios'   //  追加
import 'bootstrap/dist/css/bootstrap.css'

Vue.config.productionTip = false

Vue.prototype.$axios = axios   //  追加

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    router,
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)
})

vueファイルでタスクの情報をAPI通信で取得します。

<template>
  <div>
    <div class="d-flex">
      <div class="col-4 bg-light rounded shadow m-3 p-3">
        <div class="h4">TODO</div>
        <div v-for="task in tasks" :key="task.id" class="bg-white border shadow-sm rounded my-2 p-4">
          <span>{{ task.title }}</span>
        </div>
      </div>
    </div>
    <div class="text-center">
      <router-link :to="{ name: 'TopIndex' }" class="btn btn-dark mt-5">戻る</router-link>
    </div>
  </div>
</template>

<script>
export default {
  name: "TaskIndex",
  data() {
    return {
      tasks: []   // 空にする
    }
  },

  created() {               //   ライフサイクルフックのcreatedを定義
    this.fetchTasks();      //   ライフサイクルフックはrailsでいうコールバック
  },

  methods: {
    fetchTasks() {
      this.$axios.get("tasks")                 //  baseURLを設定しているのでurlを省略できる
        .then(res => this.tasks = res.data)    //  取得したtaskのデータをtasksプロパティに代入
        .catch(err => console.log(err.status));
    }
  }
}
</script>

<style scoped>
</style>

完成画面

f:id:study-output:20210621091030p:plain

【Vue.js】ヘッダーとフッターをコンポーネントに分ける

はじめに

ヘッダーとフッターをコンポーネントとして分ける。

前提

下記のヘッダーとフッターの部分をコンポーネントとして分けます。

<template>
  <div class="d-flex flex-column min-vh-100">
    <header class="mb-auto">
      <nav class="navbar navbar-dark bg-dark">
        <span class="navbar-brand mb-0 h1">{{ title }}</span>
      </nav>
    </header>
    <div class="text-center">
      <h3>タスクを管理しよう!</h3>
      <div class="mt-4">生活や仕事に関するタスクを見える化して抜け漏れを防ぎましょう。</div>
      <router-link :to="{ name: 'TaskIndex' }" class="btn btn-dark mt-5">はじめる</router-link>
    </div>
    <footer class="mt-auto text-center">
      <small>Copyright &copy; 2020</small>
    </footer>
  </div>
</template>

<script>
export default {
  name: "TopIndex",
  data() {
    return {
      title: "タスク管理アプリ"
    }
  }
}
</script>

<style scoped>
</style>
<template>
  <div>
    <router-view />
  </div>
</template>

ヘッダーとフッターのファイルを作成

新しくcomponentsディレクトリを作って、その配下にヘッダーとフッターのファイルを作成します。

$ mkdir app/javascript/components

$ touch app/javascript/components/TheHeader.vue

$ touch app/javascript/components/TheFooter.vue

コンポーネントを作成

続いて、先程作成したファイルにヘッダーとフッターをコンポーネントとして作成します。

<template>  
  <header>
    <nav class="navbar navbar-dark bg-dark">
      <span class="navbar-brand mb-0 h1">タスク管理アプリ</span>
    </nav>
  </header>
</template> 

<script>
export default {
  name: "TheHeader"
}
</script>
<template>  
  <footer class="text-center">
    <small>Copyright &copy; 2020</small>
  </footer>
</template>

<script>
export default {
  name: "TheFooter"
}
</script>

コンポーネントをローカル登録して呼び出す

javascript/app.vueファイルにヘッダーとフッターのコンポーネントをローカル登録して、テンプレート内で呼び出します。

<template>
  <div class="d-flex flex-column min-vh-100">
    <TheHeader class="mb-auto" />  // コンポーネントを呼び出す
    <router-view />
    <TheFooter class="mb-auto" />  // コンポーネントを呼び出す
  </div>
</template>

<script>
import TheHeader from './components/TheHeader'
import TheFooter from './components/TheFooter'
// 先程作成したファイルからコンポーネントを読み込む

export default {
  components: {    // 読み込んだコンポーネントを定義
    TheHeader,
    TheFooter
  }
}
</script>

javascript/top/index.vueファイルを修正

javascript/top/index.vueファイルからヘッダーとフッターの部分を削除します。

<template>
  <div class="text-center">
    <h3>タスクを管理しよう!</h3>
    <div class="mt-4">生活や仕事に関するタスクを見える化して抜け漏れを防ぎましょう。</div>
    <router-link :to="{ name: 'TaskIndex' }" class="btn btn-dark mt-5">はじめる</router-link>
  </div>
</template>

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

<style scoped>
</style>

【Vue.js】VueRouterを使ってルーティングを作成

はじめに

vue.jsでVueRouterを使ってルーティングを作成する。

yarnを使ってVueRouterをインストール

$ yarn add vue-router

VueRouterの初期設定

import Vue from "vue";
import Router from "vue-router";

import TopIndex from "../pages/top/index";
import TaskIndex from "../pages/task/index";

Vue.use(Router)

const router = new Router({
  mode: "history",
  routes: [
    {
      path: "/",
      component: TopIndex,
      name: "TopIndex",
    },
    {
      path: "/tasks",
      component: TaskIndex,
      name: "TaskIndex",
    },
  ],
})

export default router

vueとVueRouterをインポートします。

import Vue from "vue";
import Router from "vue-router";

画面遷移先のファイルをコンポーネントとしてインポートします。

import TopIndex from "../pages/top/index";
import TaskIndex from "../pages/task/index";

モジュールシステムを使う際に、明示的にモジュールをインストールする必要があるため下記の記載をします。

Vue.use(Router)

VueRouterのインスタンスを作成します。

const router = new Router({
  mode: "history",  // HTML5 Historyモードを使用
  routes: [
    {
      path: "/",
      component: TopIndex,
      name: "TopIndex",
    },
    {
      path: "/tasks",
      component: TaskIndex,
      name: "TaskIndex",
    },
  ],
})

VueRouterのインスタンスのrouterをエクスポートして、他のファイルでインポートできるようにします。

export default router

<router-view>コンポーネントを記載

<template>
  <div>
    <router-view />  // ルーティングにマッチしたコンポーネントを描画
  </div>
</template>

hello_vue.jsにVueRouterのファイルを読み込む

import Vue from 'vue'
import App from '../app.vue'
import router from '../router'  // 追加:先程のrouterを読み込む
import 'bootstrap/dist/css/bootstrap.css'

Vue.config.productionTip = false

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    router,  // vueインスタンス生成時のオプションに追加
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)
})

各ページのファイルの設定

<template>
  <div class="d-flex flex-column min-vh-100">
    <header class="mb-auto">
      <nav class="navbar navbar-dark bg-dark">
        <span class="navbar-brand mb-0 h1">{{ title }}</span>
      </nav>
    </header>
    <div class="text-center">
      <h3>タスクを管理しよう!</h3>
      <div class="mt-4">生活や仕事に関するタスクを見える化して抜け漏れを防ぎましょう。</div>
      <router-link :to="{ name: 'TaskIndex' }" class="btn btn-dark mt-5">はじめる</router-link>
        //  <router-link>はaタグみたいな感じ
        //  ルーティングの設定でnameプロパティを設定したのでリンク先をnameで指定できる
    </div>
    <footer class="mt-auto text-center">
      <small>Copyright &copy; 2020</small>
    </footer>
  </div>
</template>

<script>
export default {
  name: "TopIndex",
  data() {
    return {
      title: "タスク管理アプリ"
    }
  }
}
</script>

<style scoped>
</style>
<template>
  <div class="d-flex flex-column min-vh-100">
    <header class="mb-auto">
      <nav class="navbar navbar-dark bg-dark">
        <span class="navbar-brand mb-0 h1">{{ title }}</span>
      </nav>
    </header>
    <div class="d-flex">
      <div class="col-4 bg-light rounded shadow m-3 p-3">
        <div class="h4">TODO</div>
        <div v-for="task in tasks" :key="task.id" class="bg-white border shadow-sm rounded my-2 p-4">
               // v-for はrailsでいうeachメソッド
          <span>{{ task.title }}</span>
        </div>
      </div>
    </div>
    <div class="text-center">
      <router-link :to="{ name: 'TopIndex' }" class="btn btn-dark mt-5">戻る</router-link>
    </div>
    <footer class="mt-auto text-center">
      <small>Copyright &copy; 2020</small>
    </footer>
  </div>
</template>

<script>
export default {
  name: "TaskIndex",
  data() {
    return {
      title: "タスク管理アプリ",
      tasks: [
        {
          id: 1,
          title: "スーパーに買い物に行く"
        },
        {
          id: 2,
          title: "子供の迎えに行く"
        },
        {
          id: 3,
          title: "新聞を解約する"
        },
        {
          id: 4,
          title: "ゴミ出しをする"
        },
      ]
    }
  }
}
</script>

<style scoped>
</style>

サーバーサイドのルーティングを集約

Rails.application.routes.draw do
  root to: 'home#index'
  get '*path', to: 'home#index'  #  追加
end

完成

path : / f:id:study-output:20210620111710p:plain

path : /tasks f:id:study-output:20210620111735p:plain

【エラー】Your bundle is locked to mimemagic (0.3.4)....の対処法

はじめに

bundle install実行時に下記のエラーに遭遇したのでその対処法。

Your bundle is locked to mimemagic (0.3.4),
but that version could not be found in any of
the sources listed in your Gemfile. If you
haven't changed sources, that means the
author of mimemagic (0.3.4) has removed it.
You'll need to update your bundle to a
version other than mimemagic (0.3.4) that
hasn't been removed in order to install.

原因

mimemagicrailsのactivestorageが依存しているGemなのですが、どうやらライセンス問題(?)などで、一部使えなくなってしまったそうです。

解決法

解決法としてはRails 5.2.5 / 6.0.3.6 / 6.1.3.1にアップデートすれば問題ないようです。

mimemagicに依存しなくなったため。

railsのバージョンを変えたくない場合

  • 下記コマンドでshared-mime-infoをインストール
$ brew install shared-mime-info
  • gemfileにgem "mimemagic", "~> 0.3.10"を追加して、bundle update mimemagicを実行すると解決します。

トークンを使ってAPIの認証機能をつくる【rails】

はじめに

トークンを発行してapiの認証機能を実装する方法について。

構成

  • userモデルに関連づけたApiKeyモデルを作成。

  • user登録時とログイン時に期限つきのトークンを作成。 (userがすでに有効なトークンを持っている場合はそれを使用)

  • レスポンスヘッダーにトークンを入れる。

  • 該当のURLにアクセスする際にトークンで認証する。

ApiKeyモデルを作成

まずはApiKeyモデルを作成します。

$ rails g model ApiKey user:references access_token:string expires_at:datetime
class CreateApiKeys < ActiveRecord::Migration[6.0]
  def change
    create_table :api_keys do |t|
      t.references :user, null: false, foreign_key: true
      t.string :access_token, null: false
      t.datetime :expires_at

      t.timestamps
      t.index :access_token, unique: true
    end
  end
end

access_tokenカラムにNOT NULL制約とインデックスを付与します。

$ rails db:migrate

モデルの関連付け

userモデルに関連付けを指定します。

has_many :api_keys, dependent: :destroy

initializeメソッドを上書き

ApiKeyの初期化時に期限つきのトークンを作成したいので、initializeメソッドを上書きします。

また、有効なトークンだけをとってくるscopeを追加します。

class ApiKey < ApplicationRecord
  belongs_to :user

  validates :access_token, presence: true, uniqueness: true

  scope :valid_expire, -> { where('expires_at > ?', Time.current) }

  def initialize(attributes = {})
    super
    self.access_token = SecureRandom.urlsafe_base64
    self.expires_at = 1.week.from_now
  end
end

トークンに関するメソッドを作成

続いて、userモデルに有効なトークンを返すメソッドを追記します。

  def grant_api_key
    return api_keys.valid_expire.first if api_keys.valid_expire.exists?
# 有効なトークンがあればその中で一番古いトークンを返す。
# なければ新しいトークンを作成。
    api_keys.create
  end

次は継承元のbase_controllerに、レスポンスヘッダーにトークンを入れる処理を書きます。

      def set_token(user)
        api_key = user.grant_api_key
        response.headers['AccessToken'] = api_key.access_token
      end

ユーザー登録時とログイン時にトークンをセットするために、先程定義したset_tokenメソッドを呼び出します。

module Api
  module V1
    class RegistrationsController < BaseController
      def create
        user = User.new(user_params)
        if user.save
          json_string = UserSerializer.new(user).serialized_json
          set_token(user) # 追加
          render json: json_string
        else
          render_400(nil, user.errors.full_messages)
        end
      end

      private

      def user_params
        params.require(:user).permit(:name, :email, :password)
      end
    end
  end
end
module Api
  module V1
    class AuthenticationsController < BaseController
      def create
        user = login(params[:email], params[:password])
        raise ActiveRecord::RecordNotFound unless user

        json_string = UserSerializer.new(user).serialized_json
        set_token(user)  # 追加
        render json: json_string
      end

      private

      def form_authenticity_token; end
    end
  end
end

これでユーザー新規作成時とログイン時に、有効なトークンがなければ発行し、レスポンスヘッダーに入れます。

そして有効なトークンがあれば、それをレスポンスヘッダーにいれる処理が完了しました。

ページアクセスする際の認証

記事一覧ページなどにアクセスする際に、先程のトークンを認証する処理をつくります。

bese_controllerにauthenticateメソッドを追加します。

module Api
  module V1
    class BaseController < ApplicationController
      include Api::ExceptionHandler
      include ActionController::HttpAuthentication::Token::ControllerMethods
      #  authenticate_or_request_with_http_tokenメソッドを使うために必要。

      private

      def set_token(user)
        api_key = user.grant_api_key
        response.headers['AccessToken'] = api_key.access_token
      end

      def authenticate
        authenticate_or_request_with_http_token do |token, _options|
          @_current_user ||= ApiKey.valid_expire.find_by(access_token: token)&.user
        end
      end

      def current_user
        @_current_user  # `_` は直接参照してほしくない変数につける。
      end
    end
  end
end

authenticate_or_request_with_http_tokenHTTPメソッドでトークンの認証をおこないます。

falseの場合はToken: Access denied.を返します。

current_userを使えるようにするためにcurrent_userメソッドも定義しています。

最後に、articles_controllerに先程定義したauthenticateメソッドを、before_actionに設定します。

module Api
  module V1
    class ArticlesController < BaseController
      before_action :authenticate  # 追加

      def index
        articles = Article.all
        json_string = ArticleSerializer.new(articles).serialized_json
        render json: json_string
      end

      def show
        article = Article.find(params[:id])
        options = { include: %i[user 'user.name' 'user.email'] }
        json_string = ArticleSerializer.new(article, options).serialized_json
        render json: json_string
      end
    end
  end
end

sorceryを使ってapiのユーザー認証をつくる【rails】

はじめに

sorceryを使ってユーザー認証機能のapiを作る準備。

前提

fast_jsonapiというserializerを使用

class UserSerializer
  include FastJsonapi::ObjectSerializer
  has_many :articles
  attributes :name, :email
end

sorceryをインストール

gem 'sorcery'

Gemfileにsorceryと記載してbundle install

下記コマンドでsorceryをインストールします。

$ rails g sorcery:install

続いて、authenticationコントローラを作成。

$ rails g controller authentications

ルーティングを追加。

resource :authentication, only: %i[create]

コントローラの中身を記述します。

module Api
  module V1
    class AuthenticationsController < BaseController
      def create
        @user = login(params[:email], params[:password])
        raise ActiveRecord::RecordNotFound unless user

        json_string = UserSerializer.new(user).serialized_json
        render json: json_string
      end

      private

      def form_authenticity_token; end
    end
  end
end

sorceryのloginメソッドで、メールアドレスとパスワードを認証します。

該当するユーザーがいない場合はエラーを返します。

ユーザーがいる場合は、json形式でユーザーの情報を返します。

確認

postmanを使ってlocalhost:3000/api/v1/authenticationにemailとpasswordを指定してpostリクエストを送ります。

すると、下記のような値が帰ってきます。

{
    "data": {
        "id": "1",
        "type": "user",
        "attributes": {
            "name": "Test1",
            "email": "test1@example.com"
        }
    }
}