LoginSignup
21
47

More than 3 years have passed since last update.

【Ruby on Rails】DM、チャット機能

Last updated at Posted at 2020-09-10

目標

chat.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

前提

※ ▶◯◯ を選択すると、説明等が出てきますので、
  よくわからない場合の参考にしていただければと思います。

流れ

1 modelの作成
2 modelの編集
3 controllerの作成
4 routingの編集
5 viewの編集

modelの作成

ターミナル
$ rails g model Room

$ rails g model Chat user_id:integer room_id:integer message:string

$ rails g model UserRoom user_id:integer room_id:integer

$ rails db:migrate

補足1【room】
ユーザー同士が会話をする部屋。

補足2【chat】
ユーザーが発言した内容を保存するテーブル。

補足3【user_room】
userとroomが多対多の関係性のため、中間テーブルとしてこれを管理。

modelの編集

下記のようなリレーションにしていきます。
スクリーンショット 2020-09-10 22.00.12.png

app/models/room.rb
  has_many :user_rooms
  has_many :chats

補足【リレーション】
room内では多くのuser_roomがあるので、1対多。
room内では多くのchatがあるので、1対多。

app/chats/room.rb
  belongs_to :user
  belongs_to :room
app/user_rooms/room.rb
  belongs_to :user
  belongs_to :room
app/models/user.rb
  has_many :user_rooms
  has_many :chats

補足【リレーション】
1ユーザーが多くのuser_roomを保有しているので、1対多。
1ユーザーが多くのchatを行うので、1対多。

controllerの作成

ターミナル
$ rails g controller chats
app/controllers/chats_controller.rb

class ChatsController < ApplicationController
  def show
    @user = User.find(params[:id])
    rooms = current_user.user_rooms.pluck(:room_id)
    user_rooms = UserRoom.find_by(user_id: @user.id, room_id: rooms)

    unless user_rooms.nil?
      @room = user_rooms.room
    else
      @room = Room.new
      @room.save
      UserRoom.create(user_id: current_user.id, room_id: @room.id)
      UserRoom.create(user_id: @user.id, room_id: @room.id)
    end
    @chats = @room.chats
    @chat = Chat.new(room_id: @room.id)
  end
  def create
    @chat = current_user.chats.new(chat_params)
    @chat.save
    redirect_to request.referer
  end

  private
  def chat_params
    params.require(:chat).permit(:message, :room_id)
  end
end

下記コメントアウトにて、分かりづらい箇所を補足。

app/controllers/chats_controller.rb
    def show
      # どのユーザーとチャットするかを取得。
      @user = User.find(params[:id])

      # カレントユーザーのuser_roomにあるroom_idの値の配列をroomsに代入。
      rooms = current_user.user_rooms.pluck(:room_id)

      # user_roomモデルから
      # user_idがチャット相手のidが一致するものと、
      # room_idが上記roomsのどれかに一致するレコードを
      # user_roomsに代入。
      user_rooms = UserRoom.find_by(user_id: @user.id, room_id: rooms)

      # もしuser_roomが空でないなら
      unless user_rooms.nil?
        # @roomに上記user_roomのroomを代入
        @room = user_rooms.room
      else
        # それ以外は新しくroomを作り、
        @room = Room.new
        @room.save
        # user_roomをカレントユーザー分とチャット相手分を作る
        UserRoom.create(user_id: current_user.id, room_id: @room.id)
        UserRoom.create(user_id: @user.id, room_id: @room.id)
      end
      @chats = @room.chats
      @chat = Chat.new(room_id: @room.id)
    end

routingの編集

config/routes.rb
  get 'chat/:id' => 'chats#show', as: 'chat'
  resources :chats, only: [:create]

viewの編集

app/view/users/show.html.erb
<% if current_user != @user %>
  <%= link_to 'chatを始める', chat_path(@user.id)%>
<% end %>
app/view/chats/show.html.erb
<%= form_with model: @chat do |f| %>
    <%= f.text_field :message %>
    <%= f.hidden_field :room_id %>
    <%= f.submit %>
<% end %>
<table>
    <thead>
        <tr>
            <td>投稿者名</td>
            <td>投稿内容</td>
        </tr>
    </thead>
    <tbody>
        <% @chats.each do |chat| %>
            <tr>
                <td><%= chat.user.name %></td>
                <td><%= chat.message %></td>
            </tr>
        <% end %>
    </tbody>
</table>

補足【f.hidden_field】
f.hidden_fieldは、表示はしていないものの、paramsとして送りたいものを送る際に活用します。

参考

P.S.

twitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

21
47
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
21
47