LoginSignup
17
23

More than 3 years have passed since last update.

[Rails]ダイレクトメッセージ(DM)機能の実装

Last updated at Posted at 2020-04-10

目標

ezgif.com-video-to-gif (1).gif

開発環境

・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
17
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
23