LoginSignup
3
2

Vueでrails apiのデータを表示させてみよう(spa)。

Last updated at Posted at 2023-09-17

まず環境はこちら

階層

├── backend
│   ├── app
│   ├── bin
│   ├── config
│   ├── db
│   ├── lib
│   ├── log
│   ├── public
│   ├── storage
│   ├── test
│   ├── tmp
│   └── vendor
└── frontend
    └── vite-project

やること

docker compose run backend bundle exec rails g model Book title:string author:string publisher:string genre:string
app/models/book.rb
class Book < ApplicationRecord
  validates :title, presence: true, length: { maximum: 100 }
  validates :author, presence: true, length: { maximum: 100 }
  validates :publisher, presence: true, length: { maximum: 50 }
  validates :genre, presence: true, length: { maximum: 50 }
end

docker compose run backend rails db:migrate
gem 'faker'
gem 'rack-cors'
docker compose run backend bundle install

docker compose build
config/seeds.rb
20.times do
  Book.create!(
    title: Faker::Book.title,
    author: Faker::Book.author,
    publisher: Faker::Book.publisher,
    genre: Faker::Book.genre
  )
end

データが入らなかった場合

docker compose run backend bash

rails cして
20.times do
  Book.create!(
    title: Faker::Book.title,
    author: Faker::Book.author,
    publisher: Faker::Book.publisher,
    genre: Faker::Book.genre
  )
end

これで入ります

docker compose run backend rails g controller api::books
config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    resources :books
  end
end
app/controllers/api/books_controller.rb
class Api::BooksController < ApplicationController
  def index
    books = Book.all

    render json: books

    # render json: {book: books}
  end

  def show
    book = Book.find(params[:id])
    render json: book
  end
end
backend/config/initializers/cors.rb
 Rails.application.config.middleware.insert_before 0, Rack::Cors do
   allow do
     origins "localhost:5173"
     resource "*",
       headers: :any,
       methods: [:get, :post, :put, :patch, :delete, :options, :head]
   end
 end
frontend/vite-project/src/lib/axios.ts
import axios from 'axios'

export default axios.create({
    baseURL: 'http://localhost:3000',
})
main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')
package.json
{
  "name": "vite-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "axios": "^1.4.0",
    "bootstrap": "^5.3.1",
    "vue": "^3.3.4",
    "vue-class-component": "^7.2.6",
    "vue-property-decorator": "^9.1.2",
    "vue-router": "^4.2.4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.2.3",
    "typescript": "^5.0.2",
    "vite": "^4.4.5",
    "vue-tsc": "^1.8.5"
  }
}
frontend/vite-project/src/App.vue

<template>
  <div class="container">
    <h1 class="#f3e5f5 purple lighten-5 center">[Rails+Vue.js]~Bookshelf~</h1>
    <div class="row #e3f2fd blue lighten-5">
      <div class="col s4 m6" v-for="book in books" :key="book.id">
        <div class="card btn">
          <span class="card-title" @click="setBookInfo(book.id)">
            {{ book.title }}
          </span>
        </div>
      </div>
    </div>
    <div class="row" v-show="bookInfoBool">
      <div class="col s12 m12">
        <div class="card blue-grey darken-1">
          <div class="card-content white-text">
            <span class="card-title">{{ bookInfo.title }}</span>
            <div class="detail">
              ・著者:{{ bookInfo.author }}
            </div>
            <div class="detail">
              ・出版社:{{ bookInfo.publisher }}
            </div>
            <div class="detail">
              ・ジャンル:{{ bookInfo.genre }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axios from 'axios';

const bookInfo = ref({});
const bookInfoBool = ref(false);
const books = ref([]);

const fetchBooks = () => {
  axios.get('http://localhost:3000/api/books').then(
    (res) => {
      books.value = res.data;
    },
    (error) => {
      console.log(error);
    }
  );
};

const setBookInfo = (id: number) => {
  axios.get(`http://localhost:3000/api/books/${id}.json`).then((res) => {
    bookInfo.value = res.data;
    bookInfoBool.value = true;
  });
};

onMounted(fetchBooks);
</script>

<style scoped></style>

完成
http://localhost:5173/

スクリーンショット 2023-09-06 232748.png

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2