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

まず環境はこちら

https://qiita.com/gabakugik/items/cded7e8aaa014025d8ba

階層

```
├── 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270337/5050c798-6f7f-44bb-04bc-e08e7121a7ca.png)