1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rails 6で認証認可入り掲示板APIを構築する #6 show, create実装

Last updated at Posted at 2020-09-11

Rails 6で認証認可入り掲示板APIを構築する #5 controller, routes実装

showテストの実装

前回のindexに続き、showのテストとcontrollerを実装していきます。
showは、パラメータのidを元にfindして返すという挙動です。

テストは正常にレスポンスが返ってくることと、存在しないIDの時に404が返ってくることあたりでしょうか。

spec/requests/v1/posts_controller.rb
...

+  describe "GET /v1/posts#show" do
+    let(:post) do
+      create(:post, subject: "showテスト")
+    end
+    it "正常レスポンスコードが返ってくる" do
+      get v1_post_url({ id: post.id })
+      expect(response.status).to eq 200
+    end
+    it "subjectが正しく返ってくる" do
+      get v1_post_url({ id: post.id })
+      json = JSON.parse(response.body)
+      expect(json["post"]["subject"]).to eq("showテスト")
+    end
+    it "存在しないidの時に404レスポンスが返ってくる" do
+      get v1_post_url({ id: post.id + 1 })
+      expect(response.status).to eq 404
+    end
+  end
...

説明が漏れていましたが、letは呼び出された時に遅延評価されます。
つまりpostという変数が呼ばれるまでは実行されず、呼ばれた時点で実行されます。

上記例だと、itブロックの中でpost.idと呼ばれた時にcreateされます。
当然、controller未実装なのでテストはコケます。

showの実装

app/controllers/v1/posts_controller.rb
...
     def show
-      # TODO
+      render json: { post: @post }
     end
...

これで追加した3テストのうち2つは通過しますが、残り1個404エラーのテストが通過しません。
RailsでRecordNotFound例外が起き、jsonじゃないレスポンスが返っちゃっていますね。

全てのcontrollerのsuperクラスであるapplication_controller.rbを修正します。

app/controller/application_controller.rb
 # frozen_string_literal: true

 #
 # controllerのsuperクラス
 #
 class ApplicationController < ActionController::API
+  rescue_from ActiveRecord::RecordNotFound, with: :render_404


+  def render_404
+    render status: 404, json: { message: "record not found." }
+   end
 end

※無駄に2行空いているのはQiitaのシンタックスハイライトがうまく効かないだけなので、本来は1行でOKです

上記のように対応することで、レコードが見つからない(ActiveRecord::RecordNotFound)例外が投げられた時にrescueされ、render_404が実行されます。
そしてstatus: 404の通り404レスポンスコードでjsonが返されます。

ここまで実装するとテストも通過します。
念の為curlでも確認してみましょう。

$ curl localhost:8080/v1/posts/0
{"message":"record not found."}
$ curl localhost:8080/v1/posts/1
{"post":{"id":1,"subject":"hoge","body":"fuga","created_at":"2020-09-05T13:50:01.797Z","updated_at":"2020-09-05T13:50:01.797Z"}}

createテストの実装

createは新しいレコードを生成するので、1レコード増えること、増えたレコードが登録時と一致すること、不正なパラメータの時に生成できないことを確認します。

spec/requests/v1/posts_controller.rb
+  describe "POST /v1/posts#create" do
+    let(:new_post) do
+      attributes_for(:post, subject: "create_subjectテスト", body: "create_bodyテスト")
+    end
+    it "正常レスポンスコードが返ってくる" do
+      post v1_posts_url, params: new_post
+      expect(response.status).to eq 200
+    end
+    it "1件増えて返ってくる" do
+      expect do
+        post v1_posts_url, params: new_post
+      end.to change { Post.count }.by(1)
+    end
+    it "subject, bodyが正しく返ってくる" do
+      post v1_posts_url, params: new_post
+      json = JSON.parse(response.body)
+      expect(json["post"]["subject"]).to eq("create_subjectテスト")
+      expect(json["post"]["body"]).to eq("create_bodyテスト")
+    end
+    it "不正パラメータの時にerrorsが返ってくる" do
+      post v1_posts_url, params: {}
+      json = JSON.parse(response.body)
+      expect(json.key?("errors")).to be true
+    end
+  end

attributes_forを使うとbuildと同じくDBにsaveしないでオブジェクトが返ってきます。
その際にActiveRecord形式ではなくシンプルなオブジェクトとして返ってくるかつ、idやcreated_at, updated_atというpost時に不要なカラムは存在しないので便利です。

なお、この際に変数名をpostにしないようご注意ください。
筆者は記事執筆当時postにしてしまい、post v1_posts_url, params: postとなりget, postのpostがオーバーライドされてテストが正常に動かない状態となりました…解消までかなり時間がかかりました:sweat_smile:

expect do post v1_posts_url, params: new_post end.to change { Post.count }.by(1)
このブロックはpostをすることでPost.countが1増加するテストとなります。expect.to eqではなくexpectがブロックになっているのがポイントです。

createの実装

controllerを実装します。

app/controllers/v1/posts_controller.rb
...

     def create
-      # TODO
+      post = Post.new(post_params)
+      if post.save
+        render json: { post: post }
+      else
+        render json: { errors: post.errors }
+      end
    end
...
$ curl localhost:8080/v1/posts -X POST -H 'Content-Type: application/json' -d '{"subject":"moge","body":"hoge"}'        
{"post":{"id":3,"subject":"moge","body":"hoge","created_at":"2020-09-06T10:31:38.375Z","updated_at":"2020-09-06T10:31:38.375Z"}}

rubocopとrspecが正常に動いたらcommit。

本記事においてとても参考にさせていただきました。ありがとうございます。
参考:Railsで超簡単API

続き

Rails 6で認証認可入り掲示板APIを構築する #7 update, destroy実装

連載目次へ

1
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?