質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

Rails : DM機能作成 メッセージのRoomがいくつも作成される

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 945

score 25

実現したいこと

Ruby on railsを用いて,ユーザとユーザがメッセージを送信しあえるDM機能を実装したいです
下記リンクを参考にコーディングしました
https://qiita.com/kaito_program/items/caea319dd44f55c15aa6

どなたかご親切なかたご教授お願いいたします

問題点

ユーザ詳細ページからDMアイコンをクリックすると

もしユーザ同士のメッセージルームがない場合、ルームを作成して、作成したルーム詳細ページに飛ぶ。 ユーザ同士のメッセージルームがある場合、そのルーム詳細ページに飛ぶ

といった条件にしたいのですが、実際に起こっている挙動はメッセージをしようとしているユーザに対して
いくつもルームをつくってしまっている状態です

例) user1がuser2とメッセージをするためのDMアイコンをクリック → room1を作成
その後 user1がuser2とメッセージをするためのDMアイコンを再びクリック→ room1のページに飛びたいが、違うroom2が作成されてしまう

コード

routes.rb

Rails.application.routes.draw do
  get 'rooms/show'
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)
  devise_for :users
  get 'home/index'
  get 'home/myself'  
  root to: "home#index"

  get 'search', to: 'classrooms#search'

  resources :classrooms, only: [:index, :show, :create] do
    resource :reviews, only: [:create]
    get :rate, on: :member
  end

  resources :users, only: [:index, :show] do
    resource :relationships, only: [:create, :destroy]
    get :follows, on: :member
    get :followers, on: :member
  end
  resources :clubs

  resources :rooms, only: [:index, :show, :create]
  resources :messages, only: [:create, :edit, :update, :destroy]

end
class Room < ApplicationRecord
  has_many :messages
  has_many :entries
  has_many :users, through: :entries
end
class Entry < ApplicationRecord
  belongs_to :user
  belongs_to :room

  #Room一部屋に一意のユーザしか入らないバリデーション
  validates :room_id, uniqueness: { scope: :user_id }
end
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  mount_uploader :image, ImageUploader

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

         devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  #DM機能のアソシエーション
  has_many :messages
  has_many :entries
  has_many :rooms, through: :entries

end
class UsersController < ApplicationController

  def index 
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
    @currentUserEntry = Entry.where(user_id: current_user.id)
    @userEntry = Entry.where(user_id: @user.id)
    unless @user.id == current_user.id
      @currentUserEntry.each do |cu|
        @userEntry.each do |u|
          if cu.room_id == u.room_id
            @haveRoom = true
            @roomId = cu.room_id
          end
        end
      end
      unless @haveRoom
        @room = Room.new
        @entry = Entry.new
      end
    end
  end
end
class RoomsController < ApplicationController

  def create
    @room = Room.create
    @joinCurrentUser = Entry.create(user_id: current_user.id, room_id: @room.id)
    @joinUser = Entry.create(join_room_params)
    redirect_to room_path(@room.id)
  end

  def show
      @room = Room.find(params[:id])
      if Entry.where(user_id: current_user.id, room_id: @room.id).present?
        @messages = @room.messages.includes(:user).order("created_at asc")
        @message = Message.new
        @anotherEntry = Entry.where(room_id: @room.id).where.not(user_id: current_user.id)
      else
        redirect_back(fallback_location: root_path)
      end
  end

  private
  def join_room_params
    params.permit(:user_id, :room_id).merge(room_id: @room.id)
  end
end
views/users/show.html.erb

<div class="container-fluid">
  <div class="row my-5">
    <div class="col-1 offset-2">
      <!-- ユーザ画像 -->
      <% if @user.image.blank? %>
        <%= image_tag 'default.jpg', class: "icon-image" %>
      <% else %>
        <img src=<%= @user.image %> class="icon_image" >
      <% end %>
      <!-- DM機能 -->
      <% unless @user.id == current_user.id %>
        <% if @haveRoom == true %>
          <%= link_to room_path(@roomId) do %>
            <i class="far fa-envelope"></i>
          <% end %>
        <% else %>
          <%= form_with model: @room, local: true do |f| %>
            <%= f.fields_for @entry do |e| %>
              <%= e.hidden_field :user_id, value: @user.id %>
            <% end %>
            <%= f.button :type => "submit", style: 'border-style: none;' do %>
                <i class='far fa-envelope'></i>
            <% end %>
          <% end %>
        <% end %>
      <% end %>
      <!-- DM機能-->
    </div>
  </div>
</div>

試したこと

参考にしたサイトでは、Roomsコントローラーのストロングパラメータのjoin_room_paramsメソッドの部分が

def join_room_params
        params.require(:entry).permit(:user_id, :room_id).merge(room_id: @room.id)
end


となっていたのですが param is missing or the value is empty: エラーが発生したので

def join_room_params
    params.permit(:user_id, :room_id).merge(room_id: @room.id)
  end


としました
自分の見解では、Roomsコントローラーのcreateアクションの部分が問題かなと思っています

@joinUser = Entry.create(join_room_params)

roomがいくつも生成されてしまうということは 中間テーブルであるEntryモデルのuser_id, room_idのカラムにroom_idが一致する
レコードがないということだと思います。
@joinUserがcreateされるときに、なにか問題が発生しているのではないかと睨んでいます
roomを作成するときのformが下のコードですがfields_forあたりが怪しいとおもっているのですが、自分ではどこが間違っているのか
わかりませんでした。

views/users/show.html.erb

<%= form_with model: @room, local: true do |f| %>
    <%= f.fields_for @entry do |e| %>
       <%= e.hidden_field :user_id, value: @user.id %>
    <% end %>
    <%= f.button :type => "submit", style: 'border-style: none;' do %>
       <i class='far fa-envelope'></i>
    <% end %>
<% end %>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

組み合わせでユニークという制限を書いていないならいくつでも出来るでしょう
Entry.create を Entry.find_or_create_by になおしてみて

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/11/19 11:19

    ご回答ありがとうございます
    ```
    class RoomsController < ApplicationController

    def create
    @room = Room.create
    @joinCurrentUser = Entry.find_or_create_by(user_id: current_user.id, room_id: @room.id)
    @joinUser = Entry.find_or_create_by(join_room_params)
    redirect_to room_path(@room.id)
    end

    ```
    変更してみましたが、ルームが生成されてしまいます

    キャンセル

  • 2020/11/20 06:29

    join_room_params ni
    user_id, room_id 以外が入っていませんか

    キャンセル

0

show.htmlのフォームタグ内にある<%= f.fields_for @entry do |e| %>のf.は、いらないのではないでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る