RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その２、Rails API編

# はじめに

RailsとNuxt3でtodoリストの作り方を
初めから丁寧に説明したいと思います。

使用pcはmacを想定しています。

完成した構成図は以下の通りです。

![aws_structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/362a1ef8-00e1-75d0-e923-ad2e59eca033.png)

また、githubレポジトリはこちらです。

https://github.com/sugiyama404/ruby_and_nuxt

各シリーズは以下の通りです。

[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その１、Rails基本設定編](https://qiita.com/sugiyama404/items/637900df3b533fd149f8)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その２、Rails API編](https://qiita.com/sugiyama404/items/acea4cc38fe7f155ab54)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その３、Nuxt.js編](https://qiita.com/sugiyama404/items/4e74c4446add5efc3669)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その４、TerraformECS前編](https://qiita.com/sugiyama404/items/4e19ac1f9be6b8213f55)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その５、TerraformECS後編](https://qiita.com/sugiyama404/items/d0e0e74628d38842c9bd)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その６、Blue/Greenデプロイ前編](https://qiita.com/sugiyama404/items/1ffb4334b3a1546b4e23)
[RailsとNuxt3でtodoリストを作ろう[REST-API/Terraform/Fargate]〜その７、Blue/Greenデプロイ後編](https://qiita.com/sugiyama404/items/ea57e8c08156bf6eca46)

# マイグレーションをしてみる

```console
rails g model todo content:text
rails db:migrate
```

![Screenshot 2023-03-26 at 20.19.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/848a084d-90c7-e857-61e4-067bcae243ce.png)

## クライアントツールで確認してみる

想定通りのテーブルが作られていると思います。

![Screenshot 2023-03-26 at 20.27.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/7c4e3015-2788-c1dc-9300-98abdefd3c18.png)

# REST APIを作ろう

## rutingを作ろう

```ruby:config/routes.rb
Rails.application.routes.draw do
  root "index#index"
  namespace 'api' do
    resources :todos, only:[:index, :show, :create, :destroy, :update] do
    end
  end
end
```

## controllerを作ろう

```console
rails g controller api::todos
```

```ruby:app/controllers/api/todos_controller.rb
class Api::TodosController < ApplicationController
    before_action :set_todo, only: [:show, :update, :destroy]
    def index
        @todos = Todo.all
        render status: :ok, json: @todos #200
    end
    def show
        render status: :ok, json: @todo
    end
    def create
        todo = Todo.new(todo_params)
        if todo.save
          render status: :created #201
        else
          render status: :unprocessable_entity #422
        end
    end
    def update
        if @todo.update(todo_params)
            render status: :accepted
        else
            render status: :unprocessable_entity
        end
    end
    def destroy
        @todo.destroy
        render status: :accepted #202
    end

    private
    def set_todo
        @todo = Todo.find(params[:id])
    end
    def todo_params
        params.require(:todo).permit(:content)
    end
end
```

## クライアントツールで確認しよう

### index
![Screenshot 2023-03-27 at 11.25.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/86159398-eb47-4db6-a781-f2eae8dfe832.png)

### show
![Screenshot 2023-03-27 at 11.26.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/e059269d-0a63-ba09-5cfe-33b3158678ba.png)

### create
![Screenshot 2023-03-27 at 11.47.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/54aa08f9-ff7c-155d-2651-5e1928b8f32b.png)

### update
![Screenshot 2023-03-27 at 11.51.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/1ad88707-821a-205d-6d4d-bb7157b4c946.png)


### destroy
![Screenshot 2023-03-27 at 11.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/212ac9b7-35c7-84ec-65c2-182c5375e2fd.png)


# rspecで単体テストを実施しよう

## factory_bot_railsをインストールしよう

コンテナの中に入り以下のコマンドを実行しよう。

```console
sed -i -e '$ a gem "factory_bot_rails", "~> 6.2.0"' ./Gemfile
bundle install
```

factory_bot用のモデルを作ろう

```console
rails g factory_bot:model todo
```

todos.rbが生成されるので、以下のようにカラムを入れよう。
{}の中は好きなコメントを入れよう。

```ruby:spec/factories/todos.rb
FactoryBot.define do
  factory :todo do
    content {"testcomment"}
  end
end
```

## モデルのテストを実施しよう

```ruby:spec/models/todo_spec.rb
require 'rails_helper'

RSpec.describe Todo, type: :model do
  it "create recode" do
    todo = FactoryBot.create(:todo)
    expect(todo).to be_valid
  end
end
```

```console
bundle exec rspec spec/models/todo_spec.rb
```

![Screenshot 2023-03-28 at 10.03.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/97f538c6-05d4-2b1e-4493-16d0ac6eafd9.png)

## コントローラーのテストを実施しよう

```ruby:spec/requests/api/todos_spec.rb
require 'rails_helper'

RSpec.describe "Api::Todos", type: :request do
  describe "POST /api/todos" do
    it "check create method" do
      valid_params = { content: "test_api" }
      header_params = { "Content-Type" => "application/json" }
      expect { post "/api/todos", params: valid_params.to_json, headers: header_params}.to change(Todo, :count).by(+1)
      expect(response.status).to eq(201)
    end
  end
  describe "GET /api/todos" do
    it "check index method" do
      FactoryBot.create(:todo)
      get '/api/todos'
      expect(response.status).to eq(200)
    end
  end
  describe "GET /api/todos/x" do
    it "check show method" do
      FactoryBot.create(:todo)
      todo = Todo.all.order(id: "DESC").limit(1)
      get "/api/todos/#{todo.ids[0]}"
      expect(response.status).to eq(200)
    end
  end
  describe "PUT /api/todos/x" do
    it "check update method" do
      todo = Todo.all.order(id: "DESC").limit(1)
      valid_params = { content: "update_api" }
      header_params = { "Content-Type" => "application/json" }
      put "/api/todos/#{todo.ids[0]}", params: valid_params.to_json, headers: header_params
      expect(response.status).to eq(202)
    end
  end
  describe "DELETE /api/todos/x" do
    it "check delete method" do
      FactoryBot.create(:todo)
      todo = Todo.all.order(id: "DESC").limit(1)
      delete "/api/todos/#{todo.ids[0]}"
      expect(response.status).to eq(202)
    end
  end
end

```

```console
bundle exec rspec spec/requests/api/todos_spec.rb
```

![Screenshot 2023-03-28 at 10.06.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/720ebc1a-3009-b1c7-f7c0-4040d5c89a83.png)

## Github actionsでテストを実施しよう

app.test-deploy.ymlにDBマイグレーション追加しよう

```yml:.github/workflows/app.test-deploy.yml
      - name: sleep for waiting launch db
        run: sleep 120s
      - name: start to db migration #<- 追加
        run: | #<- 追加
          docker compose exec apserver rails db:migrate #<- 追加
      - name: unit testting
        run: |
          docker compose exec apserver bundle exec rspec
      - name: Docker Down
        run: docker compose down
```

### Githubで結果を確認しよう

以下のようになったと思います。

![Screenshot 2023-03-28 at 10.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/85b5e1b2-eeeb-8aae-8289-0b3cb975185e.png)