LoginSignup
17
15

More than 5 years have passed since last update.

Railsで入れ子のリソースに対してCRUD操作を行うAPIを作成する

Posted at

はじめに

今回はRails5のAPIモードを利用してRest API(以下API)を作成する手順を説明します。
作成するAPIは1:多の関連を持つモデルに対してCRUD操作を行うAPIです。まずは親テーブル(1:多の1に該当するほう)に関するAPIを作成し、その後入れ子の形で子テーブル(1:多の多に該当するほう)を作成していきます。ソースコードの雛形はscaffoldで作成します。
また、APIの検証方法としてseeds.rbにテストデータを用意し、curlコマンドで確認を行うという方法をとります。
CRUD操作を行うAPIを作成後、追加機能として検索機能を作成します。

APIの概要

今回作成するAPIについてですが、先ほども説明をしたように、1:多の関連を持つモデルに対してCRUD操作を行うAPIです。
詳細は以下のようになっています。

ルーティング

以下が最終的に作成するAPIのルーティングになっています。

$ rails routes
        Prefix Verb   URI Pattern                              Controller#Action
 search_events GET    /events/search(.:format)                 events#search
event_comments GET    /events/:event_id/comments(.:format)     comments#index
               POST   /events/:event_id/comments(.:format)     comments#create
 event_comment GET    /events/:event_id/comments/:id(.:format) comments#show
               PATCH  /events/:event_id/comments/:id(.:format) comments#update
               PUT    /events/:event_id/comments/:id(.:format) comments#update
               DELETE /events/:event_id/comments/:id(.:format) comments#destroy
        events GET    /events(.:format)                        events#index
               POST   /events(.:format)                        events#create
         event GET    /events/:id(.:format)                    events#show
               PATCH  /events/:id(.:format)                    events#update
               PUT    /events/:id(.:format)                    events#update
               DELETE /events/:id(.:format)                    events#destroy

ER図

以下が今回登場するテーブルのER図です。Eventが親テーブルにあたり、Commentが子テーブルにあたります。

ER.png

親テーブルに対するAPIの作成

まずは、親テーブルにあたるEventモデルのCRUD APIを作成する手順について説明します。

APIの作成

APIモードでプロジェクトを作成します。

$ rails new railsAPI-OneToMany --api

scaffoldで親テーブルとなるEventモデルを作成します。

$ rails g scaffold Event title:string body:text

DBにテーブルを作成します。(Rails5からrakeコマンドがrailsに統合されています。)

$ rails db:migrate

DBに接続すると、eventsテーブルが作成されているのがわかります。

$ rails dbconsole

SQLite version 3.14.0 2016-07-26 15:17:14
Enter ".help" for usage hints.

sqlite> .tables
ar_internal_metadata  events                schema_migrations

sqlite> .schema events
CREATE TABLE "events" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar, "body" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);

テストデータの作成

seeds.rbにテストデータを作成します。

db/seeds.rb
Event.create({title: 'event1 title', body: 'this is the body of event1'})
Event.create({title: 'event2 title', body: 'this is the body of event2'})

seeds.rbに作成したテストデータをDBに保存するには以下のコマンドで行います。

$ rails db:seed

APIの検証

rooutesコマンドを確認すると、現時点では以下のようなルーティングになっているのがわかります。

$ rails routes
Prefix Verb   URI Pattern           Controller#Action
events GET    /events(.:format)     events#index
       POST   /events(.:format)     events#create
 event GET    /events/:id(.:format) events#show
       PATCH  /events/:id(.:format) events#update
       PUT    /events/:id(.:format) events#update
       DELETE /events/:id(.:format) events#destroy

サーバーを起動します。

$ rails s

http://localhost:3000/events にアクセスして、以下のような結果が表示されればOKです。

[
  {
    "id": 1,
    "title": "event1 title",
    "body": "this is the body of event1",
    "created_at": "2017-01-01T07:09:22.348Z",
    "updated_at": "2017-01-01T07:09:22.348Z"
  },
  {
    "id": 2,
    "title": "event2 title",
    "body": "this is the body of event2",
    "created_at": "2017-01-01T07:09:22.356Z",
    "updated_at": "2017-01-01T07:09:22.356Z"
  }
]

http://localhost:3000/events/1 にアクセスしてid1のEventのデータだけ返されればOKです。

{
  "id": 1,
  "title": "event1 title",
  "body": "this is the body of event1",
  "created_at": "2017-01-01T07:09:22.348Z",
  "updated_at": "2017-01-01T07:09:22.348Z"
}

子テーブルに対するAPIの作成

次に、子テーブルにあたるCommentモデルのCRUD APIを作成する手順について説明します。

APIの作成

まずは先ほどと同様にscaffoldで子要素となるCommentモデルを作成します

$ rails g scaffold Comment event:references body:text

DBにテーブルを作成します。

$ rails db:migrate

1:多の関係にするために親テーブルにあたるEventモデルを以下のように変更します。
これで、一つのEventに対して複数のCommentが紐づくようになります。

class Event < ApplicationRecord
+ has_many :comments
end

親子関係のテーブルに対するAPIなので、ルーティングも入れ子になるようにroutes.rbを以下のように変更します。

config/routes.rb
Rails.application.routes.draw do
-  resources :comments
-  resources :events
+  resources :events do
+    resources :comments
+  end
end

Commentモデルのcomments_controller.rbの編集をしていきます。
変更が必要になるメソッドはindexcreateset_userです。
locationを削除する理由としては、削除しないとNoMethodError: undefined method comment_urlというエラーが出るためです。


def create
-   @comment = Comment.new(comment_params)
+   @event = Event.where(:id => params[:event_id]).first
+   @comment = @event.comments.build(comment_params)

if @comment.save
-    render json: @comment, status: :created, location: @comment
+    render json: @comment, status: :created

def index
-   @comments = Comment.all
+   @event = Event.where(:id => params[:event_id]).first
+   @comments = @event.comments.all
  render json: @comments
end

def set_comment
-   @comment = Comment.find(params[:id])
+   @event = Event.where(:id => params[:event_id]).first
+   @comment = @event.comments.where(:id => params[:id]).first
end

テストデータの作成

seeds.rbにテストデータを追加します。
上半分はid1の、下半分はid2のEventに紐づくCommentのテストデータです。

seeds.rb
Comment.create({body: 'comment1 body of Event1', event_id: 1})
Comment.create({body: 'comment2 body of Event1', event_id: 1})
Comment.create({body: 'comment3 body of Event2', event_id: 2})
Comment.create({body: 'comment4 body of Event2', event_id: 2})

rails db:seedを複数回実行することによって同じテストデータが入らないようにするためは、以下のように実行します。
はじめのコマンドで既存のテーブルに存在するデータをまっさらな状態になり、そのあとのコマンドでテストデータが作成されます。

$ rails db:migrate:reset
$ rails db:seed

APIの検証

rooutesコマンドを確認すると、以下のようなルーティングになっているのがわかります。

$ rails routes
Prefix Verb   URI Pattern                              Controller#Action
event_comments GET    /events/:event_id/comments(.:format)     comments#index
       POST   /events/:event_id/comments(.:format)     comments#create
event_comment GET    /events/:event_id/comments/:id(.:format) comments#show
       PATCH  /events/:event_id/comments/:id(.:format) comments#update
       PUT    /events/:event_id/comments/:id(.:format) comments#update
       DELETE /events/:event_id/comments/:id(.:format) comments#destroy
events GET    /events(.:format)                        events#index
       POST   /events(.:format)                        events#create
 event GET    /events/:id(.:format)                    events#show
       PATCH  /events/:id(.:format)                    events#update
       PUT    /events/:id(.:format)                    events#update
       DELETE /events/:id(.:format)                    events#destroy

サーバーを起動します。

$ rails s

Getメソッドの検証

以下のようにして、id1のEventに紐づくCommentを取得できればOKです。

$ curl http://localhost:3000/events/1/comments/

[{"id":1,"event_id":1,"body":"comment1 body of Event1","created_at":"2017-01-01T07:09:22.392Z","updated_at":"2017-01-01T07:09:22.392Z"},{"id":2,"event_id":1,"body":"comment2 body of Event1","created_at":"2017-01-01T07:09:22.401Z","updated_at":"2017-01-01T07:09:22.401Z"}]%  

POSTメソッドの検証

以下のようにして、新しいEventを作成できればOKです。

$ curl -v -H "Accept: application/json" -H "Content-type: application/json" POST -d '{"title":"event3 title", "body":"this is the body of event3"}' http://localhost:3000/events

以下のようにして、id1のEventに紐づく新しいCommentを作成できればOKです。

$ curl -v -H "Accept: application/json" -H "Content-type: application/json" POST -d '{"body":"comment3 body of Event1"}' http://localhost:3000/events/1/comments

DELETEメソッドの検証

以下のようにして、id3のEventを削除できればOKです。

$ curl -X DELETE http://localhost:3000/events/3

以下のようにして、id1のEventに紐づくid5のCommnetを削除できればOKです。

$ curl -X DELETE http://localhost:3000/events/1/comments/5

PUTメソッドの検証

以下のようにして、id2のEventを編集できればOKです。

$ curl -X PUT -H 'Content-Type:application/json' -d '{ "event" : { "title": "Event2 title" } }' http://localhost:3000/events/2

検索機能の追加

上記の方法でCRUD操作を行うAPIを作成できました。
ここでは追加機能として、Eventをtitle名で検索するAPIを作成します。

まずはコントローラーに検索用のメソッドを作成します。

events_controller.rb
def search
  @events = Event.find_by_title(params[:title])
  render json: @events
end

routes.rbを以下のように変えます。これで一番はじめに掲載したルーティングになります。

routes.rb
Rails.application.routes.draw do
  resources :events do
+    collection do
+     get :search
+    end
     resources :comments
  end
end

APIの検証

URIを直接叩いて検証する場合は以下のようになります。
event1 titleというタイトルのEventが返ってくればOKです。

http://localhost:3000/events/search?title=event1 title にアクセスして、以下のような結果が表示されればOKです。

{
  "id": 1,
  "title": "event1 title",
  "body": "this is the body of event1",
  "created_at": "2017-01-01T07:09:22.348Z",
  "updated_at": "2017-01-01T07:09:22.348Z"
}

curlなら以下のようにして確認します。

$ curl -X GET -d "title=event1 title" http://localhost:3000/events/search

{"id":1,"title":"event1 title","body":"this is the body of event1","created_at":"2017-01-01T07:09:22.348Z","updated_at":"2017-01-01T07:09:22.348Z"}%

参考

17
15
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
17
15