1
3

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.

Rails6+Reactで付箋アプリっぽいページを作ってみた。2 (API作成編)

Last updated at Posted at 2020-05-15

記事について

前回、モデルの作成まで行ったので、Reactで作ったUIとやり取りするためのAPIを用意してみます。

ここで作成するAPIは以下の二つにします。(作成とか削除とかはまた今度。。)
・ユーザ毎のタスク一覧の取得
・タスクの押し付け・・・もとい、タスク所有ユーザの更新

関連する記事

書いているうちに分量がすごくなって記事を分割したので、リンク先をまとめておきます。
その1(環境構築〜モデル作成編)
その2(API作成編)
その3(UI作成編1)
その4(UI作成編2)
その5(react-contenteditable導入編)
おまけ(モデルのテスト編)

ユーザ毎タスク一覧の取得

RailsでAPIを作成する際に作るのはControllerとViewです。
ユーザの一覧を取得したいので、"api/users/user_task_list"のようにアクセスできればなと。

コントローラの生成

ということで、コントローラを生成してもらいます。

shell
# 以下のコマンドで、viewの追加やroute.rbの編集も行ってくれます。
# APIにスタイルはいらないので、--no-stylesheetsをつけてみました。
bundle exec rails g controller API::Users user_task_list --no-stylesheets

コントローラの編集

生成されたコントローラに実際に処理を追加してみます。

app/controllers/api/users_controller.rb
class Api::UsersController < ApplicationController
  def user_task_list
    # ユーザ情報を取得してインスタンス変数に格納しておく。
    @users = User.all(); # <= 追加する処理
  end
end

jbuilderファイルの作成

React用のAPIなのでデータのやりとりは、JSONで行うのが楽です。
ということで、ユーザデータをJSONで出力するためのテンプレートファイルを追加してあげます。
名前は、app/views/api/users/list.json.jbuilderとなります。

app/views/api/users/user_task_list.json.jbuilder
# jbuilderでは好きな形でデータが出力できます。
json.users @users do | user |
  json.id(user.id);
  json.name(user.name);
  json.tasks do
    user.tasks.each do | task |
      json.set! task.id do
        json.id(task.id);
        json.title(task.title);
        json.description(task.description);
        json.due_date(task.due_date.strftime("%Y-%m-%d"));
      end
    end
  end
end

# こんなイメージのjsonデータになります。
# あとで、IDをキーにタスクデータを取得したいので、ちょっと変な形になってます。
# {
#   users: [ {
#        id: 1
#        name: "Not Assigned"
#        tasks: { 
#          "1" : { id: 1, title: "test001", description: ...},
#          "3" : { id: 3, title: "test003", description: ...}
#        }
#      }, {
#        id: 2
#        name: "Alice"
#        tasks: { 
#          "2" : { id: 2, title: "test002", description: ...}
#        }
#      }
#   ]
# }

テストしてみます。

これで、ユーザ一覧をJSONデータとして出力できるようになったはず。
と言うことで、テストしてみます。
ここでは、以下のようなテストコードをテストコードに追加してみました。

test/controllers/api/users_controller_test.rb(抜粋です。)
  test "should get user_task_list.json" do
    # jsonフォーマット指定でGETリクエストを投げます。
    get api_users_user_task_list_url(:json)

    # 200OKが返ってくるはず。
    assert_response :success

    # Boby部をJSONデータに変換
    json_data = ActiveSupport::JSON.decode(@response.body);

    # usersの配列の長さは3のはず(fixtureで3人作っていれば)
    assert_equal(3, json_data['users'].length);

  end

テスト実行

shell
# うまくいったら喜ぼう。
bundle exec rails test test/controllers/api/users_controller_test.rb

タスクの押し付け

それでは、タスク所有ユーザ切り替え用のAPIを準備していきます。

コントローラの生成

ということで、コントローラの作成です。
内部的にはタスクのユーザIDを切り替えるので、'switch_user'の名前でアクションを追加します。

shell
bundle exec rails g controller API::Tasks switch_user --no-stylesheets

# おや、なんか変だ。。
# route.rbに"get 'tasks/switch_user'"を追加したと言っている。
      create  app/controllers/api/tasks_controller.rb
       route  namespace :api do
  get 'tasks/switch_user'
end

route.rbの修正

先ほどの結果で、switch_userアクションの呼び出しメソッドが"GET"になってしまったので、route.rbを修正します。(更新ならPUTがいいかな?と。)

config/route.rb
  # 変更箇所の前後のみ記載しております。
  namespace :api do
    put 'tasks/switch_user'  # <= getからputに変更します。
  end

コントローラの編集

それでは、追加されたtasks_controller.rbを編集して、switch_userアクションを実装します。
なお、ここで大事になるのはリクエストデータのもらい方。
今回は、以下のような形でもらうことを想定した実装としています。

リクエストデータイメージ
{
  "switch_info": { 
    "task_id": 1, 
    "user_id": 2 
  }
}

switch_userアクションの内容は、以下のとおり、変更対象のタスクのユーザデータを入れ替えて、更新する処理となります。
後々、エラー処理がしやすいように、エラーメッセージを返すための仕組みも入れてあります。

app/controllers/api/tasks_controller.rb(抜粋です。)
  # タスク押し付け処理
  def switch_user
    # エラーメッセージを入れるための配列を用意しておきます。
    @errors = [];

    # 許可済みのパラメータを生成します。(switch_uesr_params()というprivateメソッドを追加しておきました。)
    suparam = switch_user_params();

    begin
      # タスクデータを取得
      @task = Task.find(suparam[:task_id]);

      # ユーザデータを取得
      @user = User.find(suparam[:user_id]);

      # タスク所有者を変更
      @task.user = @user;

      # タスクデータを更新
      if ! @task.save then
        # 失敗したら、show_errorというテンプレートを使ってエラー情報を返すようにしました。
        @errors.push("failed to switch user: task.save() faield");
        render :show_error
      end

    rescue => ex
      # 例外発生時もshow_errorというテンプレートを使って例外メッセージを返すようにしました。
      @errors.push("failed to switch user: an exception occurred.");
      @errors.push(ex.to_s);
      render :show_error
    end

  end

  private
    # task_idとuser_idだけを許可済みパラメータとして返します。
    def switch_user_params()
      return params.require(:switch_info).permit(:task_id, :user_id);
    end

jbuilderファイルの準備

ここでは、処理結果をJSON形式で返すため、以下2つパターンでjbuilderファイルを用意します。
エラーがない場合は、更新後のタスクデータを。 => switch_user.json.jbuilder
エラーがあった場合は、エラーメッセージを。 => show_error.json.jbuilder

まず、更新成功時に返すswitch_user.json.jbuilder

app/views/api/tasks/switch_user.json.jbuilder
# task { id: 1, title: "hoge" ...}というような形で返します。
json.task do
  json.id(@task.id);
  json.title(@task.title);
  json.description(@task.description);
  json.due_date(@task.due_date.strftime("%Y-%m-%d %H:%M:%S"));
  json.user_id(@task.user.id);
end

次にエラー情報を返すshow_error.json.jbuilder

app/views/api/tasks/show_error.json.jbuilder
# @errorsと言う名前の配列にエラー情報を入れてあるので、その中身を出力してあげます。
json.errors @errors do | msg |
  json.message(msg);
end

テストしてみます。

これで、適切なパラメータでリクエストを投げれば、タスクの担当者が切り替わるはずです。
ので、やっぱりテストしてみます。

テスト内容はこちら!
・ユーザの切り替えがうまく行くこと。
・失敗したらエラー情報がもらえること。

test/controllers/api/tasks_controller_test.rb(抜粋です。)
  # 正常パターン
  test "should success to switch user" do
    notassigned = users(:notassigned);
    alice = users(:alice);
    task1 = notassigned.tasks[0];

    # aliceのタスクが増えるはず。
    assert_difference 'alice.tasks.count' do
      # リクエスト投げてみる。
      put(api_tasks_switch_user_url(:json), params: { switch_info: { task_id: task1.id, user_id: alice.id } });
 
      # 200OKのはず
      assert_response :success

      # 念のためリロード
      alice.tasks.reload();
      notassigned.tasks.reload();

    end

    # レスポンスから、JSONデータを取得
    json_data = ActiveSupport::JSON.decode(@response.body);

    # タスクデータのユーザIDがaliceのIDになるはず。
    assert_equal(alice.id, json_data['task']['user_id']);

    # notassignedさんのタスクが0個になるはず。
    assert_equal(0, notassigned.tasks.count);

  end

  # 存在しないユーザに切り替えるとエラーになるはず。
  test "should fail to swith user if user is not exist" do
    # 新しいユーザを作る。が、保存しない。
    new_user = User.new(name: "Bab");

    # タスクデータのインスタンスを取得
    task2 = tasks(:task2);

    # 保存してないユーザに割り当ててみよう。
    put(api_tasks_switch_user_url(:json), params: { switch_info: { taks_id: task2.id, user_id: new_user.id } });

    # 一応200OK。
    assert_response :success

    json_data = ActiveSupport::JSON.decode(@response.body);

    # エラー情報が返されるはず。
    assert(json_data['errors'].count > 0);

  end

テストOKであれば、一応APIは出来上がりと言うことにしよう!!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?