コロナで無職になった私がエンジニアになるまで

コロナの影響で前職をクビになってから、エンジニアを目指してます。

オリジナルアプリ作成記 8 ~ チャットルームの実装 2 ~

チャットルームの実装の続き。
昨日の記述のままだと指名した人物との1対1のチャットはできない。
できるけども、チャットルームのURLを直接入力さえしてしまえば
誰でも入室できるような状態である。
同じプロジェクトで動いているメンバー同士でチャットするなら問題はないが
今回実装したいチャットルームは1対1限定なので、アクセス制限をする必要がある。


アクセス制限するための準備

新しい部屋を作るときに送られる情報に注目する。

f:id:Kosei_Program:20210117233002p:plain


inputで送るデータは選択したuser_idとcurrent_user.idで配列でuser_idsとしてデータを送っている。
この結果、中間テーブルに二人分のユーザーが保存される。

f:id:Kosei_Program:20210117233310p:plain

そのためにもroom_controllerのcreateアクションを編集し直す。
ストロングパラメーターで保存するuser_idをuser_ids, としておくことで、
上で送られたデータを保存することができる。

この配列に保存されたuser_idsを利用して、アクセス制限をする。


アクセス制限

直接roomにアクセス制限をかけるというよりは、チャット画面に移動しなければいい
=>アクセス制限するのはチャット画面。
 =>チャット画面のcontrollerを編集する。

f:id:Kosei_Program:20210117233844p:plain

まず言わずもがなログインしていないとアクセスできないようにするために
before_actionで authenticate_user!を使用する。
deviseを導入している時に使用できるメソッド。
次にroom_idを取得して、それに紐づいているuser_idを調べてみる。
ここでテーブルを注目しすぎて勘違いしてしまったのが、
RoomUser.find(params[:room_id])で中間テーブルから該当する部屋のidを取得して、紐づいているuser_idを取得しようと思った。
部屋のidは取得することはできるが、送られているuser_idはそもそも配列なのでuser_idではうまく取得することはできない。

ではroomコントローラーのストロングパラメーターに注目してみると、
~~.permit(:name, user_ids: )
としているため、配列でデータが送られている。
この配列ごとを取得して、ログインしているuser_idが配列内になければ〜という条件分岐をすればいいのではないかと考えた。

よって取得するroom_idは、Roomモデルから取得する。
ここから紐づいているuser_idsを取得する。
@room.users.idsで取得できる。
(正直この記述も何回もエラーを出しながら記述した内容なので、結果的にこうなった感じがあるけども。)

unlessを使って記述すると 論理演算子を使えないような場合でも否定系の条件を記述をすることができる。
例えば、配列内に含まれているかどうかを調べたい時に使用するinclude?メソッドは
論理演算子を使用しないので、普通では含まれている場合のみの分岐しかできない。
ここでは「含まれていなければ〜」と記述したいので、

unless @room.users.ids.include?(current_user.id)

と記述する。
@room(選択した部屋)のusers.ids(紐づいているuser_id)にinclude?(current_user.id)(今ログインしているuser_id)は含まれていなければ?
というような条件分岐ができる。
ここでは、含まれていなければトップページへ飛ばすようにしている。
マイページからアクセス、記事一覧からアクセスと言ったようにいろんな場所からアクセスすることを考慮して、一番最初に戻るようにしたほうが何かと都合がいいかなと思ったため。
まぁなんとなくだけども。

長くなったけど、アクセス制限は条件分岐で自分のidと比較するパターンが多いので、
そこをどれと比較するのかというのと、比較対象をどうやって持ってくるのか
これが問題点になる。