rails DM機能実装
DM機能の作成
今回はDM機能を作成していきます。
テーブル
ユーザーを管理するUsersテーブル
ユーザーはRoomsテーブルに属していて、相互フォロワー同士で1つずつチャットルームが作られていく。(1つのチャットルームに入るユーザーは2人(複数))
1人1人のユーザーは他のユーザーと相互フォロー関係になり、たくさんのチャットルームを持つ可能性がある。そのため、UsersテーブルとRoomsテーブルは多対多の関係!
この様な多対多の関係をテーブルにする場合に、必要なものが中間テーブル。
Entriesテーブルでチャットルームに入っているユーザー情報を管理
また、Roomsでは複数(2人)のユーザーが複数のメッセージを送るので多対多の関係。
Messagesテーブルでユーザーが送ったメッセージ情報を管理
model
テーブルを作成したところで次はmodelの作成。
足りないmodelを追加していきます。
rails g model room user:references
rails g model Entry user:references room:references
rails g model message user:references room:references message:text
rails db:migrate
アソシエーション
has_many :messages, dependent: :destroy
has_many :entries, dependent: :destroy
has_many :messages, dependent: :destroy
has_many :entries, dependent: :destroy
belongs_to :user
belongs_to :room
belongs_to :user
belongs_to :room
validates :message, presence: true, length: { maximum: 140 }
下の1行は空欄不可、140字以内に設定。
コントローラの作成
rails g controller rooms
rails g controller messages
ルーティングの設定
resources :messages, only: [:create]
resources :rooms, only: [:create,:show]
コントローラの設定
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:show]
def show
@user = User.find(params[:id])
@currentUserEntry=Entry.where(user_id: current_user.id)
@userEntry=Entry.where(user_id: @user.id)
if @user.id == current_user.id
else
@currentUserEntry.each do |cu|
@userEntry.each do |u|
if cu.room_id == u.room_id then
@isRoom = true
@roomId = cu.room_id
end
end
end
if @isRoom
else
@room = Room.new
@entry = Entry.new
end
end
end
わかりにくい部分のみ解説します。
@currentUserEntry=Entry.where(user_id: current_user.id)
@userEntry=Entry.where(user_id: @user.id)
roomがcreateされた時に現在ログインしているユーザーと、
「チャットへ」ボタンを押されたユーザーの両方をEntriesテーブルに記録する必要があるので、
whereメソッドを使いもう1人のユーザーを検索。
if @user.id == current_user.id
else
@currentUserEntry.each do |cu|
@userEntry.each do |u|
if cu.room_id == u.room_id then
@isRoom = true
@roomId = cu.room_id
end
end
end
if @isRoom
else
@room = Room.new
@entry = Entry.new
end
end
はじめに、現在ログインしているユーザーではないという条件をつけ,
すでにroomが作成されている,いない場合に分岐。
作成されている場合、 @currentUserEntryと@userEntryをeachで一つずつ取り出し、
それぞれEntriesテーブル内にあるroom_idが共通しているユーザー同士に対して
@roomId = cu.room_idという変数を指定する。
これですでに作成されているroom_idを特定する。
@isRoom = trueは、falseのとき(Roomを作成するとき)の条件を分岐するための記述。
次にroomのcontrollerを設定します。
class RoomsController < ApplicationController
before_action :authenticate_user!
def create
@room = Room.create(user_id: current_user.id)
@entry1 = Entry.create(:room_id => @room.id, :user_id => current_user.id)
@entry2 = Entry.create(params.require(:entry).permit(:user_id, :room_id).merge(:room_id => @room.id))
redirect_to "/rooms/#{@room.id}"
end
def show
@room = Room.find(params[:id])
if Entry.where(:user_id => current_user.id, :room_id => @room.id).present?
@messages = @room.messages
@message = Message.new
@entries = @room.entries
#Roomで相手の名前表示するために記述
@myUserId = current_user.id
else
redirect_back(fallback_location: root_path)
end
end
end
ここでは、Room以外にモデルのEntryもcreateさせなければいけないので、
Entriesテーブルに入る相互フォロー同士のユーザーを保存させるための記述を行う。
、@entry1は、現在ログインしているユーザーに対して
EntriesテーブルにRoom.createで作成された@roomに紐づくidと、
現在ログインしているユーザーのidを保存させる
@entry2では、フォローされている側の情報をEntriesテーブルに保存するための記述。
users/show.html.erbのfields_for @entryで保存したparamsの情報(:user_id, :room_id)を
許可し、現在ログインしているユーザーと同じく@roomにひもづくidを保存する記述をしている。
class MessagesController < ApplicationController
before_action :authenticate_user!, :only => [:create]
def create
if Entry.where(:user_id => current_user.id, :room_id => params[:message][:room_id]).present?
@message = Message.create(params.require(:message).permit(:message,:user_id, :content, :room_id).merge(:user_id => current_user.id))
redirect_to "/rooms/#{@message.room_id}"
else
redirect_back(fallback_location: root_path)
end
end
end
ビューの作成
<% unless @user.id == current_user.id %>
<% if (current_user.following? @user) && (@user.following? current_user) %>
<% if @isRoom == true %>
<p class="user-show-room"><a href="/rooms/<%= @roomId %>" class="btn btn-primary btn-lg">チャットへ</a>
<% else %>
<%= form_for @room do |f| %>
<%= fields_for @entry do |e| %>
<%= e.hidden_field :user_id, value: @user.id %>
<% end %>
<%= f.submit "チャットを始める", class:"btn btn-primary btn-lg user-show-chat"%>
<% end %>
<% end %>
<% end %>
<% end %>
<% @entries.each do |e| %>
<% if @myUserId != e.user.id %>
<h2><%= e.user.name %>さんとのトークルーム</h2>
</div>
<% end %>
<% end %>
<%= link_to "ユーザー一覧に戻る", users_path %>
<% if @messages.present? %>
<% @messages.each do |m| %>
<% @myUserId == m.user.id %>
<p><%= m.user.name %></p>
<p><%= m.message %></p>
<% end %>
<% end %>
<%= form_for @message do |f| %>
<%= f.text_field :message, placeholder: "メッセージを入力して下さい" , size: 50, class:"form-text-field" %>
<%= f.hidden_field :room_id, value: @room.id %>
<%= f.submit "投稿",class: 'form-submit'%>
<% end %>
最後に
今までで一番理解に苦しみました。
理解しにくい部分があればコメントをいただけるとありがたいです。
Discussion