3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails】相互フォロー同士のDM機能(非同期通信)

Last updated at Posted at 2022-12-27

初めに

私は普段、適当にプログラミングを勉強している@takakouと申します。今回作成した「相互フォロー同士の「DM機能(非同期通信)」は自分のアプリに、相互フォローをしているユーザ同士の1対1のDM機能を実装したい方向けです。色々DM機能の作成方法について記事を漁ってみたのですが、相互フォローしているユーザ同士の1対1のDM機能に特化した記事が少ないと感じたため、今回の記事の執筆に至りました。

前提

 フォロー・フォロワー機能が実装されているという前提のもと今回の記事を執筆していきます。前提としての機能が完成していない場合は下記の@Hbk__17さんの執筆された記事を参考にしていただき、フォロー・フォロワーの機能を実装していただくことを推奨いたします。

動作環境

・PC : MacBook Air(M1,2020)
・RAM : 8GB
・OS : macOS Monterey(ver12.1)
・Ruby : 3.1.2
・Rails : 6.1.6.1
・Bootstrap : 4.5

レイアウトを整えるのはメインをBootstrap、サブでstyleオプション等用います。流行りのCSSフレームワーク等は取り入れてません。レイアウトは割と適当なので完成後にアレンジすることをお勧めいたします。

静的コード解析ツールRubocopを用いてコードの修正をしてあります。

構成

DM機能でよくみる構成が下記になります。
image.png
上記のテーブル構成でも問題なくDM機能を実装することができますが、roomを作り、そこに人が入ることによりDM機能を作成しているのでLINEで言うグループ機能っぽい構成になってます。しかし、1対1のDM機能を実装するだけだったらこんなにテーブルは要らないので、今回は別の構成でDM機能の作成を行います。

今回作成するDM機能の構成が下記になります。
image.png

usersテーブルと、中間テーブルのmessagesテーブルを用いて実装をしていきます。

モデルの作成

Messageモデルを作成するにあたりまずは下記のコマンドを実行していただくようにお願いいたします。

terminal
rails g model Message send_user_id:integer receive_user_id:integer chat:string

migrationを行う。

terminal
rails db:migrate

モデルの記述

リレーションを設定する。今回はsend_user_idとreceive_user_idの親modelが両方ともUserになっているのでそれぞれの指定を行います。class_nameなどの記述がわからない方は下記の記事を参考にしてみてください。

message.rb
class Message < ApplicationRecord
  belongs_to :send_user, class_name: 'User'
  belongs_to :receive_user, class_name: 'User'
  validates :chat, presence: true
end

UserやRelationshipのモデルの作成や記述は終わっている前提ですので記述はしません。

リレーションの確認

1.データ作成

terminal
@message=Message.new(send_user_id:1,receive_user_id:2,chat:"こんにちは")
@message.save

事前にユーザの登録などをしておいてください。

2.作成したデータの検索

terminal
@message=Messgae.find(1)

3.リレーションの確認

terminal
 pry(main)> @message.send_user
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, email: "a@a.a", name: "koki", introduction: "eee", created_at: "2022-08-20 12:01:32.485377000 +0000", updated_at: "2022-08-20 17:40:23.711492000 +0000">
[9] pry(main)> @message.receive_user
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
=> #<User id: 2, email: "jjj@jjj", name: "aaa", introduction: "", created_at: "2022-08-20 17:40:44.220449000 +0000", updated_at: "2022-12-17 09:52:31.508726000 +0000">

リレーションが通っていることが確認できたらモデルの記述は以上になります。

messagesコントローラの作成

terminal
rails g controller messages

コントローラにおいて、相互フォローの確認の処理も行っています。

messages_controller
class MessagesController < ApplicationController
  before_action :check, only: [:message]
  def message
    @message = Message.new
    @messages = Message.where(send_user_id: current_user.id,
                              receive_user_id: params[:id]).or(@receive_messages = Message.where(send_user_id: params[:id],
                                                                                                 receive_user_id: current_user.id)).order(:created_at)
  end

  def create
    @message = Message.new(message_params)
    @message.send_user_id = current_user.id
    if @message.save!
      @messages = Message.where(send_user_id: current_user.id,
                                receive_user_id: params[:message][:receive_user_id]).or(@receive_messages = Message.where(
                                  send_user_id: params[:message][:receive_user_id], receive_user_id: current_user.id
                                )).order(:created_at)
    else
      @message = Message.new
      @messages = Message.where(send_user_id: current_user.id,
                                receive_user_id: params[:message][:receive_user_id]).or(@receive_messages = Message.where(
                                  send_user_id: params[:message][:receive_user_id], receive_user_id: current_user.id
                                )).order(:created_at)
      render :message
    end
  end

  private

  def message_params
    params.require(:message).permit(:receive_user_id, :chat)
  end

  def check
    # #自分自身とのDMを防ぐ
    if params[:id] == current_user.id
      redirect_back fallback_location: root_path
    else
      ## 相互にフォローしているかの確認。
      check1 = Relationship.exists?(followed_id: params[:id], follower_id: current_user.id)
      check2 = Relationship.exists?(follower_id: params[:id], followed_id: current_user.id)
      redirect_back fallback_location: root_path if !check1 || !check2
    end
  end
end

routeの記述

routes.rbに下記の文を追加

routes.rb
  get 'messages/:id' => 'messages#message', as: 'message'
  post 'messages' => 'messages#create', as: 'messages'

viewファイルの作成

views/messagesフォルダ配下にmessage.html.erbを作成

message.html.erb
<div class="container bg-dark">
    <div id="messages">
      <%= render 'messages',messages:@messages%>
    </div>
  <div class="row">
    <%= form_with model:@message ,url:messages_path,method: :post,local:false ,class:"w-100",html: { id: 'message_form' } do |f| %>
      <div class="d-flex justify-content-center">
        <%= f.text_field :chat ,class:"w-75",placeholder:"ここにチャットを入力してください",id:"message_field" %>
        <%= f.hidden_field :receive_user_id,value: params[:id]%>
        <%= f.submit "送信" ,class:"btn btn-secondary w-25",id:"message-btn"%>
      </div>
    <% end %>
  </div>
</div>

非同期処理でチャット欄を更新するために一部テンプレートファイルも作成しておきます。

_message.html.erb
<div class="row d-block bg-dark pt-1" style="height:800px;overflow: scroll;" >
  <div>
    <% messages.each do |message|%>
      <% if message.send_user.id==current_user.id%>
        <div class="mb-1 d-flex">
          <%= image_tag message.send_user.get_profile_image(50,50),class:"rounded ml-1 mr-2"%>
          <div class="rounded bg-success text-black text-break" style="max-width:50%"><%= message.chat %></div>
        </div>
      <% else %>
        <div class="d-flex flex-row-reverse mb-1">
          <div><%= image_tag message.send_user.get_profile_image(50,50),class:"rounded ml-2 mr-1"%></div>
          <div class="rounded bg-secondary text-white text-break mw-100" style="max-width:50%;"><%= message.chat %></div>
        </div>
      <% end %>
    <% end %>
  </div>
</div>

非同期通信でメッセージを更新する用のjsファイルも作成します。

create.js.erb
$("#messages").html("<%= j(render 'messages/messages',messages: @messages) %>");
$("#message_field").val('');

完成形

完成すると下記の図のようなレイアウトでDM機能ができるようになっているはずです!
image.png

終わりに

 「もっとこうすると良い」等の修正依頼は随時受け付けておりますので指摘をお願いいたします。少しでも、どこかの誰かの役に立ってくれれば、とても嬉しいです。
 

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?