エンジニア転職日記

エンジニア転職に向けての日記です

DM機能の実装(チャットルーム管理)

概要

DB設計に引き続き、オリジナルアプリのDM機能を実装していきます。

今回はチャットルーム管理機能の実装です。

 

shangang7321.hatenablog.com

 

実装の流れ

以下のGIF画像のように実装します。

f:id:shangang7321:20200827084625g:plain

流れとしては、

①メンタープロフィールの「チャットで相談する」ボタンを押す

②カレントユーザーとメンターの2人が属しているチャットルームを生成

③チャット画面に遷移

④チャット一覧には相手の名前が表示される

の順番で処理が行われています。

 

実装

まずは、roomsモデル、roomsテーブルを作成します。

% rails g model room

 

マイグレーションファイルはこのように設定します。name(ルーム名)は、基本的にチャット相手の名前を表示するのでnullを許可しています。

class CreateRooms < ActiveRecord::Migration[6.0]
def change
create_table :rooms do |t|
t.string :name
t.timestamps
end
end
end

 

マイグレートします。

% rails db:migrate

 

roomsコントローラーを生成します。

% rails g controller rooms

 

アクションを定義します。

 
def index
end
 
def new
@room = Room.new
end

 

ルーティングを設定します。

resources :rooms, only: [:index,:new,:create]

 

usersテーブルとroomsテーブルは多対多の関係なので、中間テーブルを用意する必要があります。

詳細はDB設計の記事で説明しています。

 

shangang7321.hatenablog.com

 

中間テーブルであるroom_userを作成します。

% rails g model room_user

 

マイグレーションファイルを編集します。

class CreateRoomUsers < ActiveRecord::Migration[6.0]
def change
create_table :room_users do |t|
t.references :room, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end

 

マイグレートします。

% rails db:migrate

 

アソシエーションを記載します。

user.rb

has_many :room_users
has_many :rooms, through: :room_users

 

room.rb

has_many :room_users
has_many :users, through: :room_users, dependent: :destroy

dependent: :destroyオプションは、親モデルが削除された時に子モデルも削除するというオプションです。これを追加すると、ルームを削除した時に中間テーブルの情報も削除します。

room_userのテーブルに外部キーを設定しているので、このオプションを付けないと外部キーエラーが発生します。

 

room_user.rb

belongs_to :room
belongs_to :user

 

次は、クライアント側からコントローラーへ渡す値を設定します。

今回のアプリでは、メンタープロフィールの詳細画面に、チャットルーム作成のリンクをとなるボタンを配置しています。

コードは以下の通りです。

<div class="chat-wrapper">
<%= link_to(rooms_path(user_ids: [current_user.id, @profile.user.id]),
method: :post) do %>
<div class="chat-btn">
<div class="chat-p">チャットで相談する</div>
<%= image_tag 'chat.png', class: 'chat-logo'%>
</div>
<% end %>
</div>

rooms_pathのmethod: :postを指定することで、roomsコントローラーのcreateアクションにつながります。

user_ids: [current_user.id, @profile.user.id]

ここの部分でuser_idsをキーとして、[自分のid,相手のid]という配列を渡しています。

 

createアクションを作成します。

def create
@room = Room.new(room_params)
@room.save
redirect_to room_messages_path(@room)
end
 
private
def room_params
params.permit(user_ids: [])
end

Roomクラスのインスタンスが生成、保存された時、パラメーターで受け取ったuser_idsが中間テーブルに保存されます。

つまり、user_ids: [1,2]というパラメーターを受け取ったとすると、

roomsテーブルにはid:1のルームのレコードが保存され、room_usersテーブルには、room_id:1、user_id:1のレコードとroom_id:1、user_id:2のレコードが保存されることになります。

user_idsを受け取るためのストロングパラメーターも設定します。

この処理が終わった後、メッセージ一覧画面に遷移しています。(Messageのルーティングは未設定のためこのままではエラーが出ます)

 

次は、チャットルーム一覧画面の表示です。

チャットルーム一覧部分のコードは以下の通りです。

<div class="rooms">
<% current_user.rooms.each do |room| %>
<div class="room">
<div class="room-name">
<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>
<%= link_to @another_user.nickname, room_messages_path(room) %>
</div>
<div class="delete-room">
<%= link_to "×", room_path(room), method: :delete %>
</div>
</div>
<% end %>
</div>

 

<% current_user.rooms.each do |room| %>

この部分でまず、自分の属しているルームを全て取り出してeach文で1つずつ処理します。

 

<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>
<%= link_to @another_user.nickname, room_messages_path(room) %>

ここでチャット相手の名前が表示されるようになっています。

仕組みとしては、@another_userに、そのルームの自分ではない方のユーザー(つまりチャット相手)の情報を代入して、その名前を表示するようにしています。

 

これで、チャットルーム管理の基本的な実装は完了です。

メッセージ送信機能に関しては別の記事で説明します。