1
2

More than 3 years have passed since last update.

DM機能実装

Last updated at Posted at 2020-08-04

自分用にまとめます。

必要なテーブル

users

ユーザーテーブル

rooms

チャットルームをするための場所

entries

チャットルームに入るユーザーを管理するテーブル

messages

メッセージを管理するテーブル

実装

モデル作成

$ rails g model room name:string
$ rails g model entry user:references room:references
$ rails g model message user:references room:references content:text
$ rails db:migrate
user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :messages, dependent: :destroy
  has_many :entries, dependent: :destroy
end
entry.rb
class Entry < ApplicationRecord
  belongs_to :user
  belongs_to :room
end
room.rb
class Room < ApplicationRecord
  has_many :messages, dependent: :destroy
  has_many :entries, dependent: :destroy
end
message.rb
class Message < ApplicationRecord
  belongs_to :user
  belongs_to :room
end



コントローラ作成

$ rails g controller users index show
$ rails g controller rooms
$ rails g controller messages
routes.rb
resources :users, only: [:show,:edit,:update]
resources :messages, only: [:create]
resources :rooms, only: [:create,:show]
users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    # current_userをEntriesテーブルから探す
    @currentUserEntry = Entry.where(user_id: current_user.id)
    # DMを送る対象のユーザーをEntriesテーブルから探す
    @userEntry = Entry.where(user_id: @user.id)

    if @user.id != current_user.id
      # currentUserと@userのEntriesをそれぞれ一つずつ取り出し、2人のroomが既に存在するかを確認
      @currentUserEntry.each do |cu|
        @userEntry.each do |u|
          # 2人のroomが既に存在していた場合
          if cu.room_id == u.room_id
            @isRoom = true
            #room_idを取り出す
            @roomId = cu.room_id
          end
        end
      end

      # 2人ののroomが存在しない場合
      unless @isRoom
        #roomとentryを新規に作成する
        @room = Room.new
        @entry = Entry.new
      end
    end
  end
end
users/show.html.slim
  - if @user.id != current_user.id

    # 相互フォローしていることが条件
    - if (current_user.following? @user) && (@user.following? current_user)

      # 既にroomがある場合(以前にDMのやりとりしている)
      - if @isRoom == true
         # そのroomに入る
         =link_to room_path(@roomId) do
           i.fas.fa-envelope

      # roomがない場合(新規のDM)
      - else
        # RoomとEntry2つのモデルにデータを送る
        = form_with @room, local: true do |f|
          = fields_for @entry do |e|
            # Entryにはuser_idを送る必要があるため、@user.idを指定
            = e.hidden_field :user_id, value: @user.id
          # 今回はリンクにアイコン使用のためbutton_tagを使用。通常であればf.submitでOK
          = button_tag type: 'submit' do
            i.fas.fa-envelope
rooms_controller
class RoomsController < ApplicationController

  def create
    @room = Room.create
    # current_userのEntry
    @entry1 = Entry.create(room_id: @room.id, user_id: current_user.id)
    # DMを受け取る側のEntry(users/showでuser_idは渡しているため、room_idを拾って、マージしている)
    @entry2 = Entry.create((entry_params).merge(room_id: @room.id))
    redirect_to room_path(@room)
  end

  def show
    @room = Room.find(params[:id])
    # entriesテーブルにcurrent_user.idと紐付いたチャットルームがあるかどうか確認
    if Entry.where(user_id: current_user.id,room_id: @room.id).present?
      @messages = @room.messages
      @message = Message.new
      # チャットルームのユーザ情報を表示させるため代入
      @entries = @room.entries
    else
      redirect_back(fallback_location: root_path)
    end
  end

  private
    def entry_params
      params.require(:entry).permit(:user_id, :room_id)
    end

end
rooms/show.html.slim
.row
  .col-lg-2
  .col-lg-8.frame-notification
    <hr>
    # メッセージがあれば、一覧を表示
    - if @messages.present?
      - @messages.each do |message|
        .row.balloon5
          # 今回は、自分のメッセージは右側に表示させたいため以下の条件分岐
          - if current_user.name == message.user.name
            .col-lg-12.text-right
              .chatting
                .say
                  = message.content
                <br>
                small= message.created_at.to_s(:datetime_jp)
          - else
            .col-lg-2.text-center
              = attachment_image_tag message.user, :image, format: 'jpeg', fallback: "noimage.png", size: "50x40"
              small= link_to message.user.name, user_path(message.user), class: "d-block mt-1"
              <br>
            .col-lg-10.text-left
              .chatting
                .says
                  p= message.content
                <br>
                small= message.created_at.to_s(:datetime_jp)
        <hr>
    - else
      p メッセージはありません。

    .row
      .col-lg-2
      .col-lg-8.text-center
        = form_with model: @message, local: true do |f|
          = f.text_field :content, placeholder: "メッセージを入力して下さい" , size: 50
          = f.hidden_field :room_id, value: @room.id
          = f.submit "投稿", class: 'btn btn-outline-secondary btn-sm ml-2'
messages_controller.rb
class MessagesController < ApplicationController

  def create
    #formで送られてきたroom_idとcurrent_user.idを持ったデータがEntryにあるかを確認
    if Entry.where(user_id: current_user.id, room_id: params[:message][:room_id]).present?
      # contentとroom_idはformで送られてきているため、user_idをマージして新規メッセージを作成
      @message = Message.create((message_params).merge(user_id: current_user.id))
      redirect_back(fallback_location: root_path)
    else
      flash[:alert] = "メッセージ送信に失敗しました。"
      redirect_back(fallback_location: root_path)
    end
  end

  private
    def message_params
      params.require(:message).permit(:user_id, :content, :room_id)
    end

end

完成!

1
2
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
1
2