#環境
macOS 10.15.7
Rails 5.2.4.4
Docker 19.03.13
#前提
●ログインユーザーと特定のユーザー同士のみがDMページへ移動してやり取りを行うことを前提
●ログインユーザーがDM中のユーザーの一覧が閲覧できるページを作成
●メニューバーからDM中のユーザーの一覧への移動が可能
#特定のユーザー同士がやり取りできるDMページの作成
まずは特定のユーザー同士がやり取りできるDMページの作成をします。
##モデルの作成
UseRoomテーブルを作成してカラムは以下のようにします。
rails g model UserRoom user_id:integer room_id:integer
Roomテーブルを作成します。
rails g model Room
messageテーブルを作成してカラムは以下のようにします。
rails g model Message user_id:integer room_id:integer message:string
次に以下のように関連付けさせます。
has_many :user_rooms
has_many :messages
belongs_to :user
belongs_to :room
has_many :user_rooms
has_many :messages
マイグレートをします。
rails db:migrate
##コントローラーの作成
rails g controller messages
コントローラーに以下のように追記します。
class MessagesController < ApplicationController
before_action :authenticate_user
def show
# これからDMを行うユーザーを取得する
@user = User.find(params[:id])
# ログイン中のユーザーのuser_roomにあるroom_idの値の配列を取得する
rooms = @current_user.user_rooms.pluck(:room_id)
# room_idが上記のroomsに一致するレコードを取得する
user_rooms = UserRoom.find_by(user_id: @user.id, room_id: rooms)
# user_roomが見つかったら@roomに代入する
unless user_rooms.nil?
@room = user_rooms.room
else
# user_roomがない場合は新しくroomを作る
@room = Room.new
@room.save
# user_roomをログインしているユーザーと相手の分を作成する
UserRoom.create([{:user_id => @current_user.id, :room_id => @room.id}, {:user_id => @user.id, :room_id => @room.id}])
end
# メッセージの履歴を取得
@messages = @room.messages
# 新規メッセージ用オブジェクトの作成
@message = Message.new(room_id: @room.id)
render("users/message_form")
end
def create
# メッセージの作成
# message_paramsからパラメータを取得する
@message = @current_user.messages.new(message_params)
@message.save
redirect_to request.referer
end
private
def message_params
params.require(:message).permit(:message, :room_id)
end
end
##routes.rbの編集
下記のコードを追記します。
get 'message/:id' => 'messages#show', as: 'message'
resources :messages, only: [:create]
##viewの作成
今回はメッセージフォームの下にユーザー同士のコメントが表示されるようになります。
<div class="dm">
<h1>DMを送る</h1>
<div class="message-form">
<%= form_with model: @message do |f| %>
<%= f.text_area :message %>
<!-- メッセージ作成時に必要な :room_idをおいておく -->
<%= f.hidden_field :room_id %>
<%= f.submit "投稿" %>
<% end %>
</div>
<table>
<thead>
<tr>
<td>投稿者名</td>
<td>投稿内容</td>
</tr>
</thead>
<tbody>
<% @messages.each do |message| %>
<tr>
<td><%= message.user.name %></td>
<td><%= message.message %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
#DM中のユーザーを一覧画面で表示
次にDM中のユーザーを一覧画面で表示できるページを作成します。
##viewの作成
viewを下記のようにします。
<% @other_rooms.each do |room| %>
<!-- やり取り相手の名前を表示 -->
<%= link_to(room.user.name, "/users/#{room.user.id}") %> <br>
<!-- やり取りの中で最新のメッセージを取得して、リンクとして表示する -->
<%= link_to(Message.find_by(id: room.room.message_ids.last)&.message, "/message/#{room.user.id}") %> <br>
<% end %>
一覧に表示させるためにこちらを追記します。
def show_last_messages
# ログイン中のユーザーのやり取り一覧を取得する
current_rooms = @current_user.user_rooms
# 空の配列を作り、ここにRoomのIDだけを格納する
my_room_ids = []
current_rooms.each do |user_room|
my_room_ids << user_room.room.id
end
# ログイン中のユーザーを相手のIDに合わせ取得しする
@other_rooms = UserRoom.where(room_id: my_room_ids).where.not(user_id: @current_user.id)
render("users/message_users.html.erb")
end
##routes.rbの編集
こちらを追記します。
get "users/last_message" => "posts#show_last_messages"
##一覧ページに飛ぶためのリンク作成
わたしの場合はメニューバーから飛べるようにしたかったため下記のように追記しました。
<ul class="header-menus">
<% if @current_user %>
<li>
<%= link_to("こんにちは!#{@current_user.name}さん", "/users/#{@current_user.id}") %>
</li>
<!--下記のように追記-->
<li>
<%= link_to("DM一覧", "/users/last_message") %>
</li>
<li>
<%= link_to("ログアウト", "/logout") %>
</li>
<% else %>
<li>
<%= link_to("新規登録", "/signup") %>
</li>
<li>
<%= link_to("ログイン", "/login") %>
</li>
<% end %>
今回は一例ですがご参考までになれたら幸いです^^