在rails聊天应用中创建3个用户之间的对话

时间:2016-10-25 21:29:11

标签: ruby-on-rails

目前,需要sender_idconversation.id才能在2个用户之间启动对话。

如果我想允许第三个用户加入对话,协会将如何运作?

当用户开始对话时,sender_id属于recipient_idvisitor_id

我希望current_userclass Conversation < ActiveRecord::Base belongs_to :sender, :foreign_key => :sender_id, class_name: 'User' belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User' has_many :messages, dependent: :destroy validates_uniqueness_of :sender_id, :scope => :recipient_id scope :involving, -> (user) do where("conversations.sender_id =? OR conversations.recipient_id =?",user.id,user.id) end scope :between, -> (sender_id,recipient_id) do where("(conversations.sender_id = ? AND conversations.recipient_id =?) OR (conversations.sender_id = ? AND conversations.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id) end end )能够加入任何对话,所有用户都能够查看所有对话。

conversation.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable


  has_many :conversations, :foreign_key => :sender_id
  after_create :create_default_conversation

user.rb

belongs_to :visitor, :foreign_key => :visitor_id, class_name: 'User'

我很好奇是否添加

很容易
class Message < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :user

  validates_presence_of :body, :conversation_id, :user_id
end

到conversation.rb模型。但我不知道如何获得属于current_user的visitor_id加入特定的对话(或让所有人都可以查看所有对话)。

编辑:添加了message.rb和控制器。

message.rb

class ConversationsController < ApplicationController
  before_filter :authenticate_user!

  layout false

  def create
    if Conversation.between(params[:sender_id],params[:recipient_id]).present?
      @conversation = Conversation.between(params[:sender_id],params[:recipient_id]).first
    else
      @conversation = Conversation.create!(conversation_params)
    end

    render json: { conversation_id: @conversation.id }
  end

  def show
    @conversation = Conversation.find(params[:id])
    @reciever = interlocutor(@conversation)
    @messages = @conversation.messages
    @message = Message.new
  end

  private
  def conversation_params
    params.permit(:sender_id, :recipient_id)
  end

  def interlocutor(conversation)
    current_user == conversation.recipient ? conversation.sender : conversation.recipient
  end
end

conversations_controller.rb

class MessagesController < ApplicationController
  before_filter :authenticate_user!

  def create
    @conversation = Conversation.find(params[:conversation_id])
    @message = @conversation.messages.build(message_params)
    @message.user_id = current_user.id
    @message.save!

    #@path = conversation_path(@conversation)
  end

  private

  def message_params
    params.require(:message).permit(:body)
  end
end

messages_controller.rb

 pbsc   qty   wt

 pbsc1   1    0  
 pbsc2   2    10
 pbsc3   1    0
 pbsc2   2    9    
 pbsc1   0    8
 pbsc4   9    9

1 个答案:

答案 0 :(得分:2)

添加:visitor将允许第三方进行最小的更改,但不允许第四或第k个额外的访问者轻松。这似乎是一个可能的场景,因此您需要一个跟踪所有users_conversations的联接表。

首先为连接表创建一个迁移:

class CreateUsersConversationsJoinTable < ActiveRecord::Migration
  def change
    create_table :users_conversations do |t|
      t.integer :user_id, null: false
      t.integer :conversation_id, null: false
    end
    add_index :users_conversations, [:user_id, :conversation_id], unique: true
  end
end

然后沿着这些方向创建一个模型:

class UsersConversations
  belongs_to :users, class_name: User, inverse_of: :users_conversations
  belongs_to :conversations, class_name: Conversation, inverse_of: :users_conversations
  validates :user_id, :conversation_id, presence: true
end

您还需要创建迁移以将发件人和收件人移动到此新模型中。

您需要将发件人属性从会话移动到邮件,并通过邮件让对话了解发件人:has_many :senders through: message, foreign_key: sender_id。这样每条消息都会跟踪其发件人。

您的接收方将成为未发送特定消息的对话中的所有用户。您的邮件类需要添加以下内容:

has_many :users_conversations, through: :conversations
has_many :receivers, -> { where('users_conversations.user_id != messages.sender_id') }, through: :users_conversations, foreign_key: :user_id, class_name: 'User'

虽然您的会话课需要更改:between以使用/替换为users,您的范围将如下所示:

scope :involving, -> (user) do
  users_conversations.where(user: user)
end

要获得所有对话,您只需在相关控制器中指定@conversations = Conversation.all,或使用控制器索引路径。