Rails APIでUser周りの実装をしたので、グループの作成とユーザーの入退会処理をしていきます。
【Rails】JWTを用いたUser周りのAPI実装
Groupテーブル
カラム名 | データ型 | 制約 | 説明 |
---|---|---|---|
id | integer | 主キー、オートインクリメント | グループの一意な識別子 |
name | string | null: false | グループ名 |
created_at | datetime | null: false | レコード作成日時 |
updated_at | datetime | null: false | レコード更新日時 |
GroupMembershipテーブル
カラム名 | データ型 | 制約 | 説明 |
---|---|---|---|
id | integer | 主キー、オートインクリメント | グループメンバーシップの一意な識別子 |
user_id | integer | null: false, foreing ket (users.id) | ユーザーID(ユーザーへの外部キー) |
group_id | integer | null: false, foreing ket (groups.id) | グループID(グループへの外部キー) |
created_at | datetime | null: false | レコード作成日時 |
updated_at | datetime | null: false | レコード更新日時 |
ルーティング
グループの作成、更新、削除、参加、退会を実装していきます。
HTTPメソッド | パス | コントローラ#アクション | 説明 |
---|---|---|---|
POST | /api/v1/groups | groups#create | グループを新規作成 |
PUT/PATCH | /api/v1/groups/:id | groups#update | グループ情報を更新 |
DELETE | /api/v1/groups/:id | groups#destroy | グループを削除 |
POST | /api/v1/groups/:id/join | group_memberships#create | 指定したグループに参加 |
DELETE | /api/v1/groups/:id/leave | group_memberships#destroy | 指定したグループから退会 |
以下がルーティングです
resources :groups do
member do
post 'join', to: 'group_memberships#create'
delete 'leave', to: 'group_memberships#destroy'
end
end
期待するレスポンス
- POST /api/v1/groups
{
"message": "グループが作成されました。",
"group": {
"id": 1,
"name": "新しいグループ",
"created_at": "2024-11-03T12:34:56Z",
"updated_at": "2024-11-03T12:34:56Z"
}
}
- PUT/PATCH /api/v1/groups
{
"message": "グループ情報が更新されました。",
"group": {
"id": 1,
"name": "更新されたグループ",
"created_at": "2024-11-03T12:34:56Z",
"updated_at": "2024-11-03T12:45:00Z"
}
}
- DELET /api/v1/groups
{
"message": "グループが削除されました。"
}
- POST /api/v1/join
{
"message": "グループに参加しました。",
"group_membership": {
"id": 1,
"user_id": 1,
"group_id": 1,
"created_at": "2024-11-03T12:34:56Z"
}
}
- DELETE /api/v1/leave
{
"message": "グループから退会しました。"
}
Groupテーブルの作成
マイグレーションの作成
docker-compose run web rails generate model Group name:string
このコマンドにより、Groupテーブルのマイグレーションファイルが生成されます。nameカラムが追加されます。
マイグレーションの実行
docker-compose run web rails db:migrate
これでGroupテーブルがデータベースに作成されます。
モデルの編集
groupのレコードが削除された時に関連するgroup_membershipsのレコードも同時に削除するように設定。
class Group < ApplicationRecord
has_many :group_memberships, dependent: :destroy
has_many :users, through: :group_memberships
end
GroupMembershipテーブルの作成
マイグレーションの作成
docker-compose run web rails generate model GroupMembership user:references group:references
このコマンドにより、GroupMembershipテーブルのマイグレーションファイルが生成されます。user_id、group_idカラムが追加されます。
user_idとgroup_idの2つの外部キーが必要です。
マイグレーションの実行
docker-compose run web rails db:migrate
これでGroupテーブルがデータベースに作成されます。
バリデーションの追加
同じユーザーが同じグループに重複して参加できないようにするためにバリデーションを追加します。
class GroupMembership < ApplicationRecord
belongs_to :user
belongs_to :group
validates :user_id, uniqueness: { scope: :group_id }
end
マイグレーションの実行
docker-compose run web rails db:migrate
これでGroupMembershipテーブルがデータベースに作成されます。
userモデルの編集
userのレコードが削除された時に関連するgroup_membershipsのレコードも同時に削除するように設定。
has_many :group_memberships, dependent: :destroy
has_many :groups, through: :group_memberships
コントローラの作成
groupsコントローラ
docker-compose exec web rails generate controller api/v1/Groups
module Api
module V1
class GroupsController < ApiController
before_action :authenticate_user
before_action :set_group, only: [:update, :destroy]
# グループを新規作成
def create
group = Group.new(group_params)
if group.save
GroupMembership.create(user: current_user, group: group)
render json: { message: "グループが作成されました。", group: { id: group.id, name: group.name } }, status: :created
else
render json: { errors: group.errors.full_messages }, status: :unprocessable_entity
end
end
# グループ情報を更新
def update
if @group.update(group_params)
render json: { message: "グループ情報が更新されました。", group: {id: @group.id, name: @group.name} }, status: :ok
else
render json: { errors: @group.errors.full_messages }, status: :unprocessable_entity
end
end
# グループを削除
def destroy
if @group.destroy
render json: { message: "グループが削除されました。" }, status: :ok
else
render json: { error: "グループの削除に失敗しました。" }, status: :unprocessable_entity
end
end
private
# Strong Parameters
def group_params
params.require(:group).permit(:name)
end
# グループを取得
def set_group
@group = current_user.groups.find(params[:id])
rescue ActiveRecord::RecordNotFound
render json: { error: "グループが見つかりません。" }, status: :not_found
end
end
end
end
group_membersipsコントローラ
docker-compose exec web rails generate controller api/v1/GroupMemberships
module Api
module V1
class GroupMembershipsController < ApiController
before_action :authenticate_user
# グループに参加
def create
group = Group.find(params[:id])
membership = current_user.group_memberships.build(group: group)
if membership.save
render json: { message: "グループに参加しました。" }, status: :created
else
render json: { errors: membership.errors.full_messages }, status: :unprocessable_entity
end
end
# グループから退会
def destroy
membership = current_user.group_memberships.find_by(group_id: params[:id])
if membership&.destroy
render json: { message: "グループから退会しました。" }, status: :ok
else
render json: { error: "退会に失敗しました。" }, status: :unprocessable_entity
end
end
end
end
end
Postmanを使ってリクエスト
Postmanを使ってそれぞれリクエストを送ってみます。
グループ作成
リクエストメソッドをPOSTに設定しURLを以下に設定する
http://localhost:3000/v1/groups
リクエストボディを以下のように設定して
{
"name": "hoge group"
}
リクエストを送ると以下のレスポンスが返ってきます。
{
"message": "グループが作成されました。",
"group": {
"id": 1,
"name": "hoge group"
}
}
グループ情報更新
リクエストメソッドをPATCHに設定しURLを以下に設定する
http://localhost:3000/v1/groups/1
リクエストボディを以下のように設定して
{
"name": "fuga group"
}
リクエストを送ると以下のレスポンスが返ってきます。
{
"message": "グループ情報が更新されました。",
"group": {
"id": 1,
"name": "fuga group"
}
}
グループ情報更新
リクエストメソッドをPATCHに設定しURLを以下に設定する
http://localhost:3000/v1/groups/1
リクエストボディを以下のように設定して
{
"name": "fuga group"
}
リクエストを送ると以下のレスポンスが返ってきます。
{
"message": "グループ情報が更新されました。",
"group": {
"id": 1,
"name": "fuga group"
}
}
グループ削除
リクエストメソッドをDELETに設定しURLを以下に設定する
http://localhost:3000/v1/groups/1
リクエストボディは設定せずにリクエストを送ると以下のレスポンスが返ってきます。
{
"message": "グループが削除されました。"
}
グループ退会
リクエストメソッドをDELETに設定しURLを以下に設定する
http://localhost:3000/v1/groups/1/leave
リクエストボディは設定せずにリクエストを送ると以下のレスポンスが返ってきます。
{
"message": "グループから退会しました。"
}