【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