#目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina
前提
下記実装済み。
・Slim導入
・Bootstrap3導入
・Font Awesome導入
・ログイン機能実装
#ダイレクトメッセージ(DM)機能を実装
1.モデル
ターミナル
$ rails g model room
ターミナル
$ rails g model entry user:references room:references
ターミナル
$ rails g model message user:references room:references body:text
ターミナル
$ rails db:migrate
schema.rb
ActiveRecord::Schema.define(version: 2020_04_05_115005) do
create_table "entries", force: :cascade do |t|
t.integer "user_id"
t.integer "room_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["room_id"], name: "index_entries_on_room_id"
t.index ["user_id"], name: "index_entries_on_user_id"
end
create_table "messages", force: :cascade do |t|
t.integer "user_id"
t.integer "room_id"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["room_id"], name: "index_messages_on_room_id"
t.index ["user_id"], name: "index_messages_on_user_id"
end
create_table "rooms", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
user.rb
class User < ApplicationRecord
has_many :entries, dependent: :destroy
has_many :messages, dependent: :destroy
end
room.rb
class Room < ApplicationRecord
has_many :entries, dependent: :destroy
has_many :messages, dependent: :destroy
end
entry.rb
class Entry < ApplicationRecord
belongs_to :user
belongs_to :room
end
message.rb
class Message < ApplicationRecord
belongs_to :user
belongs_to :room
end
2.コントローラー
ターミナル
$ rails g controller rooms index show
ターミナル
$ rails g controller messages
users_controller.rb
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
# Entryモデルからログインユーザーのレコードを抽出
@current_entry = Entry.where(user_id: current_user.id)
# Entryモデルからメッセージ相手のレコードを抽出
@another_entry = Entry.where(user_id: @user.id)
unless @user.id == current_user.id
@current_entry.each do |current|
@another_entry.each do |another|
# ルームが存在する場合
if current.room_id == another.room_id
@is_room = true
@room_id = current.room_id
end
end
end
# ルームが存在しない場合は新規作成
unless @is_room
@room = Room.new
@entry = Entry.new
end
end
end
end
rooms_controller.rb
def create
room = Room.create
# Entryモデルにログインユーザーのレコードを作成
current_entry = Entry.create(user_id: current_user.id, room_id: room.id)
# Entryモデルにメッセージ相手のレコードを作成
another_entry = Entry.create(user_id: params[:entry][:user_id], room_id: room.id)
redirect_to room_path(room)
end
def index
# ログインユーザーが属しているルームのIDを全て抽出して配列化
current_entries = current_user.entries
my_room_ids = []
current_entries.each do |entry|
my_room_ids << entry.room.id
end
# さらにuser_idがログインユーザーでは無いレコードを抽出
@another_entries = Entry.where(room_id: my_room_ids).where.not(user_id: current_user.id)
end
def show
@room = Room.find(params[:id])
@message = Message.new
# メッセージ相手を抽出
@another_entry = @room.entries.find_by('user_id != ?', current_user.id)
end
messages_controller.rb
class MessagesController < ApplicationController
def create
message = Message.new(message_params)
message.user_id = current_user.id
if message.save
redirect_to room_path(message.room)
else
redirect_back(fallback_location: root_path)
end
end
def destroy
message = Message.find(params[:id])
message.destroy
redirect_back(fallback_location: root_path)
end
private
def message_params
params.require(:message).permit(:room_id, :body)
end
end
3.ルーティング
routes.rb
Rails.application.routes.draw do
resources :messages, only: [:create, :destroy]
resources :rooms, only: [:create, :index, :show]
end
4.ビュー
users/index.show.slim
.row
.col-xs-2
.col-xs-8
table.table
thead
tr
th
| 氏名
th
| 自己紹介
th
th
tbody
tr
td
= @user.name
td
= @user.introduction
td
- unless @user.id == current_user.id
- if @is_room == true
= link_to 'メッセージ', room_path(@room_id), class: 'btn-sm btn-success'
- else
= form_with model: @room, url: rooms_path, local: true do |f|
= fields_for @entry do |e|
= e.hidden_field :user_id, value: @user.id
= f.submit 'メッセージ', class: 'btn-sm btn-success'
td
- if @user == current_user
= link_to '編集', edit_user_path(@user), class: 'btn-sm btn-primary'
.col-xs-2
rooms/show.html.slim
.row
.col-xs-3
.col-xs-6
.page-header
h3
= link_to @another_entry.user.name, user_path(@another_entry.user)
table.table
thead
tr
th
| 送信者
th
| メッセージ
th
tbody
- @room.messages.each do |message|
tr
td
= link_to user_path(message.user) do
= message.user.name
td
= message.body
td
- if message.user == current_user
= link_to '削除', message, method: :delete, data: { confirm: '本当に削除してもよろしいですか?' }, class: 'btn-sm btn-danger'
br
.col-xs-3
.row
.col-xs-3
.col-xs-6
= form_with model: @message, url: messages_path, local: true do |f|
.col-xs-10
= f.text_field :body, class: 'form-control'
= f.hidden_field :room_id, value: @room.id
.col-xs-2
= f.submit '送信', class: 'btn btn-info btn-block'
.col-xs-3
rooms/index.html.erb
.row
.col-xs-3
.col-xs-6
table.table
thead
tr
th
| メッセージ相手
th
| メッセージ内容
tbody
- @another_entries.each do |entry|
tr
td
= link_to entry.user.name, user_path(entry.user)
td
= link_to room_path(entry.room) do
/ 最後に送られたメッセージを表示
= Message.find_by(id: entry.room.message_ids.last)&.body
.col-xs-3