🐣
[Ruby on Rails] DM機能の作成
今回は相互フォローしている人限定で、DM機能が使用出来る様にします
文字制限は140字まで送信可能にします
- DM機能には4つのテーブルを使用します
- Users テーブル
- Rooms テーブル
- Entries テーブル
- Messages テーブル
テーブルの設計
- Rooms テーブル
カラム名 | データ型 | カラムの説明 |
---|---|---|
user | refaremces | userのテーブルを指定 |
- Entries テーブル
カラム名 | データ型 | カラムの説明 |
---|---|---|
user | refarences | userのテーブルを指定 |
room | refarences | roomのテーブルを指定 |
- Messages テーブル
カラム名 | データ型 | カラムの説明 |
---|---|---|
user | refarences | userのテーブルを指定 |
room | refarences | roomのテーブルを指定 |
message | text | メッセージを送る際の文字列 |
- refareneces 新しく作成するテーブルのカラムに、作成済ののテーブルを指定する場合に使います
モデルの作成
$ rails g model Rooms user:refarences
$ rails g model Entries user:refarences room:refarences
$ rails g model Messages user:refarences room:refarences message:text
モデルの関連付け
user.rb
has_many :messages, dependent: :destroy
has_many :entries, dependent: :destroy
room.rb
belongs_to :user
has_many :messages, dependent: :destroy
has_many :entries, dependent: :destroy
entry.rb
belongs_to :user
belongs_to :room
message.rb
belongs_to :user
belongs_to :room
validates :message, presence: true, length: {maximum: 140}
プチ解説
- presence: true は存在しなければいけない つまり文字を入力しないと送信できない
- length 配列に入っている数を数える
- maximum: 140 文字制限を140字までに設定
作成した、テーブルの内容を含めてモデルを作成します
ルーティングの設定
routes.rb
resources :messages, only: [:create]
resources :rooms, only: [:create, :show]
コントローラーの変更
user_controller
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
解説
わかりにくいので、今回使用しない記述は消しています
@
- where テーブル内の条件に一致したレコードを配列の形で取得することができるメソッド
- Entry モデルから ログインしているユーザーの id を取得
- Entry モデルから選択したユーザーの id を取得
if @user
- ログインしている user であるという条件をつけます
- else でログインしてるユーザーでなかったらとします
unless
を使用しても平気です - room が作成されている場合とされていない場合に条件分岐させます
- cu.room_id == u.room_id で2つのroomのid が同じであるとする
- true でroomが存在していることを書きます
if @isRoom
- else で room が存在していない場合とします
- Room の新しいインスタンスと Entry の新しいインスタンスを作成します
View 画面の変更
users/show.html.erb
<% 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">chatへ</a>
<% else %>
<%= form_for @room do |f| %>
<%= fields_for @entry do |e| %>
<%= e.hidden_field :user_id, value: @user.id %>
<% end %>
<%= f.submit "chatを始める", class:"btn btn-primary btn-lg user-show-shat" %>
<% end %>
<% end %>
<% end %>
<% end %>
解説
unless
- unless を使用し、現在ログインしているユーザーではなかったらと条件をつけます
- 2行目の if で相互フォローしていると条件をつけます
- 3行目の if で room がすでにある場合とない場合で条件分岐します
- room がすでにある場合は roomId を指定し、room へのリンクをつけます
else
- form_for rails で情報を送信するためのメソッドで使い方は
<%= from_for('モデルクラスのインスタンス') do |f| %>
- fields_for 同じフォームで別のモデルオブジェクトも編集したい場合に使用する
- hidden_field form_with や form_for タグの中でパラメーターをユーザーが直接フォームから入力させないまま、値を受け渡したい時に使用するもの
- value は値を指定します
コントローラーの作成
Room のコントローラーを作成します
$ rails g controller Rooms show
続いてコントローラーを定義します
rooms_controller
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
@myUserId = current_user.id
else
redirect_to root_path
end
end
解説
create
- Room.create で room を作成し、 ログインしているユーザーの id を渡します
- Entry.create で entryを作成し、 @room の id とログインしているユーザーの id を渡します
- merge 他の条件と結合するという意味で、使い方は
モデル.merge(他の条件,*rest)
- paramsで受け取ったデータと @room の id を結びつけています
show
- where メソッドはテーブル内の条件に一致したレコードを配列の形で取得することができるメソッド
- present メソッドは変数の値が存在するかしないかによって後続の処理を変更したい場合に使用するメソッド
romms/show ページの作成
rooms/show.html.erb
<% @entries.each do |e| %>
<% if @myUserId != e.user.id %>
<h2><%= e.user.name %></h2>
<% end %>
<% end %>
<% 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, class:"form-text-field" %>
<%= f.hidden_field :room_id, value: @room.id %>
<%= f.submit "投稿" %>
<% end %>
ユーザーの名前とメッセージが送れるよう作成
レイアウトなどはお好みで
コントローラーを定義
messages_controller
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
最後に messages_controller にメッセージを create させる記述をします
こちらの記事を参考にさせて頂きました
Discussion