※この記事に登場するソースコードは僕個人が開発しているプロジェクトのもので仕事とは無関係です
ざっくり説明
この記事の続きです。
サービスクラスができたので今回はコントローラーを作っていきます。
POST /api/v1/folder_transfer で別のユーザーにフォルダを送信できるようにします
実装していく
まずはテスト。例によってインターフェースだけ確認できる簡単なテストを書きます。
require 'test_helper' class Api::V1::FolderTransferControllerTest < ActionDispatch::IntegrationTest setup do @sender = users(:kentas) @recipient1 = users(:some_user1) sign_in(@sender) @folder = @sender.folders.create(name: 'folder') end test "create action should send a folder to recipient" do folder_transfer_params = { folder_transfer: { folder_id: @folder.id, recipient_usernames_or_emails: ['some_user1'], } } post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true assert_response 201 end end
routeを定義していないので当然失敗します
# Running: E Error: Api::V1::FolderTransferControllerTest#test_create_action_should_send_a_folder_to_recipient: NameError: undefined local variable or method `api_v1_folder_transfer_index_url' for #<Api::V1::FolderTransferControllerTest:0x00007fffc14c7098> test/controllers/api/v1/folder_transfer_controller_test.rb:23:in `block in <class:FolderTransferControllerTest>' rails test test/controllers/api/v1/folder_transfer_controller_test.rb:16
route追加
namespace :api, { format: 'json' } do namespace :v1 do resources :folder_transfer, only: [:create] end end
Controller作成
class Api::V1::FolderTransferController < ApplicationController before_action :authenticate_user! def create render json: {}, status: 201 end end
とりあえず先ほどのテストはパスするようになります
Run options: --seed 62470 # Running: . Finished in 0.575040s, 1.7390 runs/s, 1.7390 assertions/s.
アサーションを追加します
こんな感じにしてみました。(我ながらこのassert_differenceもっとどうにかなるだろ、、)
test "create action should send a folder to recipient" do folder_transfer_params = { folder_transfer: { folder_id: @folder.id, recipient_usernames_or_emails: ['some_user1'], } } assert_difference '@recipient1.folders.count', 1 do assert_difference '@recipient1.folders.first.try(:images).try(:count).to_i', 3 do post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true assert_response 201 json = JSON(response.body) assert_equal(["some_user1に3個の画像を送信しました"], json["messages"]) end end end
走らせると当然失敗します
Run options: --seed 35602 # Running: F Failure: Api::V1::FolderTransferControllerTest#test_create_action_should_send_a_folder_to_recipient [/home/kenta-s/Repositories/oak/test/controllers/api/v1/folder_transfer_controller_test.rb:29]: Expected: ["some_user1に3個の画像を送信しました"] Actual: nil rails test test/controllers/api/v1/folder_transfer_controller_test.rb:22
テストが通るようにコントローラーを実装していきます。ガーっと書きました
class Api::V1::FolderTransferController < ApplicationController before_action :authenticate_user! def create service = FolderTransferService.new( sender: current_user, folder: current_user.folders.find(folder_transfer_params[:folder_id]), recipient_usernames_or_emails: folder_transfer_params[:recipient_usernames_or_emails], ) if service.call render json: {messages: service.messages}, status: 201 else render json: {}, status: 422 end end private def folder_transfer_params params.require(:folder_transfer).permit(:folder_id, recipient_usernames_or_emails: []) end end
適当に書いたので落ちるかと思ったんですが一発で通ってしまいました。
Run options: --seed 59691 # Running: . Finished in 0.667398s, 1.4984 runs/s, 5.9934 assertions/s. 1 runs, 4 assertions, 0 failures, 0 errors, 0 skips
不安なので異常系のテストも書いておきます
test "create action should not send a folder when invalid username is given" do folder_transfer_params = { folder_transfer: { folder_id: @folder.id, recipient_usernames_or_emails: ['non_existing_user'], } } assert_no_difference 'Folder.count' do assert_no_difference 'Image.count' do post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true assert_response 201 # 複数のユーザーのうち、一人だけ失敗するようなことがあるのでステータスコードは常に201を返します json = JSON(response.body) assert_equal(["ユーザーが見つかりませんでした: non_existing_user"], json["error_messages"]) end end end
error_messagesを返すように書いていないので失敗します
Run options: --seed 25534 # Running: F Failure: Api::V1::FolderTransferControllerTest#test_create_action_should_not_send_a_folder_invalid_username_is_given [/home/kenta-s/Repositories/oak/test/controllers/api/v1/folder_transfer_controller_test.rb:47]: --- expected +++ actual @@ -1 +1 @@ -["ユーザーが見つかりませんでした: non_existing_user"] +nil rails test test/controllers/api/v1/folder_transfer_controller_test.rb:40
error_messagesを返すようにします
def create service = FolderTransferService.new( sender: current_user, folder: current_user.folders.find(folder_transfer_params[:folder_id]), recipient_usernames_or_emails: folder_transfer_params[:recipient_usernames_or_emails], ) if service.call render json: {messages: service.messages, error_messages: service.error_messages}, status: 201 else render json: {error_messages: service.error_messages}, status: 422 end end
通るようになりました
Run options: --seed 18876 # Running: .. Finished in 0.659569s, 3.0323 runs/s, 12.1291 assertions/s. 2 runs, 8 assertions, 0 failures, 0 errors, 0 skips
コントローラーもとりあえずこれで完成とします。 全体が動くようになったらもう少しテストケースを追加します。
続きは別記事で書きます。