【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>
完成画面