2016-02-23 3 views
0

Я работаю над системой обмена сообщениями в моем приложении rails. Я уже работаю правильно для отправки сообщений между двумя пользователями (отправителем и получателем). Эта настройка прекрасна, но как я могу сделать новый разговор для каждой комнаты, чтобы проверка уникальности была только между пользователем и комнатой или наоборот? Каждому пользователю разрешено отправлять сообщения в комнату со страницы показа номера. Поэтому room_id может быть доставлен туда. У одного пользователя может быть много списков, что усложняет для меня. Смутно, какое изменение сделать в приведенном ниже коде для этого? Или мне нужно сделать другой подход к дизайну для моделей? У меня есть user, listing, conversation и message модельличная система обмена сообщениями в рельсах

conversation.rb

class 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 

Message.rb

class Message < ActiveRecord::Base 
     belongs_to :conversation 
     belongs_to :user 

     validates_presence_of :content, :conversation_id, :user_id 

     def message_time 
     created_at.strftime("%v") 
     end 
    end 


conversations_controller.rb 

class ConversationsController < ApplicationController 
    before_action :authenticate_user! 

    def index 
      @conversations = Conversation.involving(current_user) 
    end 

    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 

    redirect_to conversation_messages_path(@conversation) 
    end 

    private 

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

messages_controller.rb

class MessagesController < ApplicationController 
    before_action :authenticate_user! 
    before_action :set_conversation 

    def index 
    if current_user == @conversation.sender || current_user == @conversation.recipient 
     @other = current_user == @conversation.sender ? @conversation.recipient : @conversation.sender 
     @messages = @conversation.messages.order("created_at DESC") 
    else 
     redirect_to conversations_path, alert: "You don't have permission to view this." 
    end 
    end 

    def create 
    @message = @conversation.messages.new(message_params) 
    @messages = @conversation.messages.order("created_at DESC") 

    if @message.save 
     redirect_to conversation_messages_path(@conversation) 
    end 
    end 

    private 

    def set_conversation 
    @conversation = Conversation.find(params[:conversation_id]) 
    end 

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

ответ

2

Ваши отношения отключены. Беседа, когда отправитель и получатель исправлены, не годится - на самом деле это просто монолог!

Вместо этого нам нужно настоящее много для многих отношение. Это означает, что нам нужно третью таблицу для хранения связь между пользователями и converstations

Так что давайте начнем с создания модели:

rails g model UserConversation user:belongs_to conversation:belongs_to 

Это будет генерировать модель и миграции для присоединения таблицы, которая соединит пользователей и разговоры. Теперь мы должны также позаботиться о требовании уникальности. Открывают миграции:

class CreateUserConversations < ActiveRecord::Migration 
    def change 
    create_table :user_conversations do |t| 
     t.belongs_to :user, index: true, foreign_key: true 
     t.belongs_to :conversation, index: true, foreign_key: true 

     t.timestamps null: false 
    end 

    # Add this constraint 
    add_index :user_conversations, [:user_id, :conversation_id], unique: true 
    end 
end 

Это ограничение, что обеспечивает уникальность на уровне базы данных и защищает от условий гонки. Мы также хотим получить подтверждение на уровне программного обеспечения.

class UserConversation < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :conversation 

    validates_presence_of :user_id, scope: :conversation_id 
end 

Теперь настройки отношения в пользователя и Собеседования, так что они идут через модель присоединиться:

class User < ActiveRecord::Base 
    has_many :user_conversations 
    has_many :conversations, through: user_conversations 

    def has_joined?(conversation) 
    conversations.where(id: conversation).exist? 
    end 
end 

class Conversation < ActiveRecord::Base 
    has_many :user_conversations 
    has_many :messages 
    has_many :users, through: user_conversations 

    def includes_user?(user) 
    users.where(id: user).exist? 
    end 
end 

Это позволяет нам сделать @user.conversations или @conversation.users. Нам не нужны хакеры.

Это пример того, как вы могли бы добавить пользователя к разговору на лету:

class MessagesController < ApplicationController 

    # ... 

    def create 
    unless current_user.has_joined?(conversation) 
     # @todo handle case where this fails 
     @conversation.users << current_user 
    end 

    @message = @conversation.messages.new(message_params) do |m| 
     # get the current user from the session or a token 
     # using params is an open invitation for hacking 
     m.user = current_user 
    end 

    if @message.save 
     redirect_to conversation_messages_path(@conversation) 
    else 
     render :new 
    end 
    end 

    # ... 
end 

Но обратите внимание, что вы до сих пор довольно путь и, вероятно, потребуется несколько различных контроллеров правильно представляют сообщения в разных контекстах:

/messages/:id => MessagesController 
/users/:user_id/messages => Users::MessagesController 
/conversations/:id/messages => Conversations::MessagesController 
+1

Это только начало того, как исправить некоторые проблемы в вашем приложении. Это очень распространенный домен, поэтому вы можете попробовать github для приложений с открытым исходным кодом с помощью системы обмена сообщениями и посмотреть, как они подходят к этим проблемам. – max

+0

Спасибо большое mate..This помогает ... Разве это не то же самое, что упоминание полиморфной истины? – Abhilash

+1

Нет, полиморфные отношения - это то, где у вас есть отношение, а тип связанной записи - динамический. Например, если у вас есть изображение, которое может принадлежать «Article» или «Slideshow». Это отношение много к большому числу через модель объединения. http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association – max

Смежные вопросы