RailsでAPIを作ってみた（後編）

こんにちは！モリタケンタロウです！
[前回](https://qiita.com/MORITAKENTARO/items/4c52276b74cd3620886e)に引き続き、Ruby on RailsでAPIを作る方法について紹介します。

* [RailsでAPIを作ってみた（前編）](https://qiita.com/MORITAKENTARO/items/4c52276b74cd3620886e)

# 開発環境
* ruby 2.6.3p62
* Rails 5.0.7.2

# Let's Try Anyway
前回は、コントローラーの作成とルーティングの設定を行いました。
今回は、モデルの作成とCRUD処理の実装を行います。

## モデルを作成
まずは、モデルを作成します。
といっても、今回は単純にテキストを格納する箱を用意してあげるだけです。

```bash
$ rails g model content text:string
```

モデルを作成したら、DBにモデルの定義を反映させます。

```bash
$ rake db:migrate
```

ちゃんとDBに反映されているかどうか確認してみます。

```bash
$ rails dbconsole
mysql> SHOW TABLES;
+---------------------------------+
| Tables_in_rails_app_development |
+---------------------------------+
| ar_internal_metadata            |
| contents                        |
| schema_migrations               |
+---------------------------------+
3 rows in set (0.00 sec)

mysql> DESCRIBE contents;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| text       | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM contents;
Empty set (0.00 sec)
```
`text`フィールドを持つ`contents`テーブルがちゃんとできていました。
もちろん中身はまだ空っぽなので、適当にデータを入れてみます。
初期データを投入したい場合は、`db/seeds.rb`を編集するようです。

```ruby:db/seeds.rb
Content.create([
  {text: "りんご"},
  {text: "みかん"},
  {text: "ぶどう"}
])
```

`rake db:seed`コマンドで初期データを投入します。

```bash
$ rake db:seed
```

改めてDBを確認してみます。

```bash
$ rails dbconsole
mysql> SELECT * FROM contents;
+----+-----------+---------------------+---------------------+
| id | text      | created_at          | updated_at          |
+----+-----------+---------------------+---------------------+
|  1 | りんご    | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  2 | みかん    | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  3 | ぶどう    | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
+----+-----------+---------------------+---------------------+
3 rows in set (0.00 sec)
```
ちゃんとDBにデータが投入されいました。

## CRUD処理を実装
それでは次に、コントローラーをいじってCRUD処理を実装してみます。
それぞれのアクションに対して↓のような処理を書きました。

```ruby:app/controllers/contents_controller.rb
class ContentsController < ApplicationController
    
    def index
        contents = Content.all
        render json: { status: 'SUCCESS', action: action_name, data: contents }
    end
    
    def create
        content = Content.new(params.require(:content).permit(:text))
        if content.save
            render json: { status: 'SUCCESS', action: action_name, data: content }
        else
            render json: { status: 'ERROR', action: action_name, data: content.errors }
        end
    end
    
    def show
        content = Content.find(params[:id])
        render json: { status: 'SUCCESS', action: action_name, data: content }
    end
    
    def update
        content = Content.find(params[:id])
        if content.update(params.require(:content).permit(:text))
            render json: { status: 'SUCCESS', action: action_name, data: content }
        else
            render json: { status: 'ERROR', action: action_name, data: content.errors }
        end
    end
    
    def destroy
        content = Content.find(params[:id])
        content.destroy
        render json: { status: 'SUCCESS', action: action_name, data: content }
    end
    
end
```

## 動作確認
それでは、早速APIの動きを確かめてみます。

```Bash
$ rails s -b 0.0.0.0 -p 3001 # アプリ起動
```
今回は[Postman](https://www.postman.com/)を使ってAPIの動作を確認します。
※ Cloud9の環境で動かすときは、セキュリティグループやVPNの設定を行って、Postmanからアプリにアクセスできるようにする必要があります。
参考：[実行中のアプリケーションをインターネット経由で共有する](https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/app-preview.html#app-preview-share)

### Index (GET http://サーバーIP:3001/contents)
Indexでは`contents`テーブルの全データを取得する処理にしています。

**レスポンス**

```json
{
    "status": "SUCCESS",
    "action": "index",
    "data": [
        {
            "id": 1,
            "text": "りんご",
            "created_at": "2020-05-10T07:38:30.000Z",
            "updated_at": "2020-05-10T07:38:30.000Z"
        },
        {
            "id": 2,
            "text": "みかん",
            "created_at": "2020-05-10T07:38:30.000Z",
            "updated_at": "2020-05-10T07:38:30.000Z"
        },
        {
            "id": 3,
            "text": "ぶどう",
            "created_at": "2020-05-10T07:38:30.000Z",
            "updated_at": "2020-05-10T07:38:30.000Z"
        }
    ]
}
```

投入した初期データがちゃんと返ってきています。

### Create (POST http://サーバーIP:3001/contents)
`Create`では、リクエストボディで渡したデータを`contents`テーブルに新たに追加する処理にしています。

**リクエスト**

```json
{
	"text": "バナナ"
}
```
**レスポンス**

```json
{
    "status": "SUCCESS",
    "action": "create",
    "data": {
        "id": 4,
        "text": "バナナ",
        "created_at": "2020-05-10T08:28:04.000Z",
        "updated_at": "2020-05-10T08:28:04.000Z"
    }
}
```
**DBの状態**

```bash
+----+--------------+---------------------+---------------------+
| id | text         | created_at          | updated_at          |
+----+--------------+---------------------+---------------------+
|  1 | りんご       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  2 | みかん       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  3 | ぶどう       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  4 | バナナ       | 2020-05-10 08:28:04 | 2020-05-10 08:28:04 |
+----+--------------+---------------------+---------------------+
```
期待通り、新しくIDが4の「バナナ」のデータが追加されています。

### Show (GET http://サーバーIP:3001/contents/:id)
Showでは、`contents`テーブル内の指定したIDのデータのみ返却する処理にしています。

**レスポンス**

```json
{
    "status": "SUCCESS",
    "action": "show",
    "data": {
        "id": 1,
        "text": "りんご",
        "created_at": "2020-05-10T07:38:30.000Z",
        "updated_at": "2020-05-10T07:38:30.000Z"
    }
}
```
IDを1に指定したので、IDが1の「りんご」のデータが取得できました。

### Update (PUT http://サーバーIP:3001/contents/:id)
Updateでは、`contents`テーブル内の指定したIDのデータを、リクエストボディで渡したデータで上書きする処理にしています。

**リクエスト**

```json
{
	"text": "キウイ"
}
```
**レスポンス**

```json
{
    "status": "SUCCESS",
    "action": "update",
    "data": {
        "id": 4,
        "text": "キウイ",
        "created_at": "2020-05-10T08:28:04.000Z",
        "updated_at": "2020-05-10T08:30:19.000Z"
    }
}
```
**DBの状態**

```bash
+----+--------------+---------------------+---------------------+
| id | text         | created_at          | updated_at          |
+----+--------------+---------------------+---------------------+
|  1 | りんご       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  2 | みかん       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  3 | ぶどう       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  4 | キウイ       | 2020-05-10 08:28:04 | 2020-05-10 08:30:19 |
+----+--------------+---------------------+---------------------+
```
IDを4に指定して「キウイ」を渡したので、IDが4の「バナナ」が「キウイ」に上書きされました。

### Destroy (DELETE http://サーバーIP:3001/contents/:id)
Destroyでは、`contents`テーブル内の指定したIDのデータを削除する処理にしています。

**レスポンス**

```json
{
    "status": "SUCCESS",
    "action": "destroy",
    "data": {
        "id": 4,
        "text": "キウイ",
        "created_at": "2020-05-10T08:28:04.000Z",
        "updated_at": "2020-05-10T08:30:19.000Z"
    }
}
```
**DBの状態**

```bash
+----+--------------+---------------------+---------------------+
| id | text         | created_at          | updated_at          |
+----+--------------+---------------------+---------------------+
|  1 | りんご       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  2 | みかん       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
|  3 | ぶどう       | 2020-05-10 07:38:30 | 2020-05-10 07:38:30 |
+----+--------------+---------------------+---------------------+
```
IDを4に指定したので、IDが4の「キウイ」が削除されました。

無事、CURD処理が実装されたAPIができました！
それでは～