0

I am creating a simple chatting app on rails 4. The controllers, models and views are created but the functionality is still incomplete. I have 2 tables in my database, conversations and messages. The conversation table holds two fields, sender id and receiver id. And the messages table holds 3 fields, body, user id and read(defaults to 0 meaning not read).

Models:

class Conversation < ActiveRecord::Base

    belongs_to :sender, :foreign_key => :sender_id, :class_name => "User"
    belongs_to :reciever, :foreign_key => :reciever_id, :class_name => "User"

    has_many :messages, :dependent => :destroy

    validates_uniqueness_of :sender_id, :scope => :reciever_id

    scope :involving, lambda { |user_id|
        where("sender_id = ? OR reciever_id = ?", user_id, user_id)
    }

    scope :between, lambda { |sender_id, reciever_id|
        where("(sender_id = ? AND reciever_id = ?) OR (sender_id = ? AND reciever_id = ?)", sender_id, reciever_id, reciever_id, sender_id)
    }

    def other_interlocutor(user_id)
        if sender.id == user_id
            return reciever.id
        else
            return sender.id
        end
    end
end

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

  validates_presence_of :conversation_id, :user_id, :body

end

What I am trying to do is to create a real-time functionality of receiving unread messages count whenever someone receives a new message. I am using private pub to create the chat between users.

I have a user model which contains this function:

def unread_messages_count
    unread_messages = 0
    # puts "Putting self conversations ! #{self.conversations.first}"
    conversations = Conversation.involving(self.id)
    conversations.each do |conversation|
        unread_messages += conversation.messages.where(:read => 0, :user_id => conversation.other_interlocutor(self.id)).count
    end
    return unread_messages = unread_messages == 0 ? nil : unread_messages
end

I have one page where all user's conversations are listed and one a conversation is clicked all the messages related to that conversation are listed too. On the same page I have subscribed every conversation_messages_path to create separate channels for every conversation. Whenever a message is sent a create.js.erb file is rendered where I publish to those subscribed channels:

<% publish_to conversation_messages_path(@conversation.id) do %>
    $("#conversations_link").text("<%= current_user.unread_messages_count %> Conversations");
    $("#messages").append("<%= escape_javascript render(:partial => 'message', :locals => { :message => @message })%>");
<% end %>

The $("#conversation_link") is where I want to show the unread messages count.

Currently, the unread messages count is returning back the wrong count and the navbar is only updated when the conversation.sender_id messages the receiver.

My unread message counter is not returning the correct number of unread messages. I don't know how to fix it. What's wrong in my code? Thanks.

4

1 回答 1

4

我会争辩说你的领域建模真的很糟糕。

对话的整个想法是,所涉及的各方轮流成为发送者和接收者。你所模仿的是独白

独白是一个人发表的演讲,或者是一场让你想把头发从无聊中拉出来的冗长的片面谈话。希腊语词根 monologos 翻译为“单独说话”,这是一个独白:一个人在说话。

您最终在此处得到的域模型应如下所示:

数据库图

它的消息实际上链接到两个(或更多)用户:thesenderrecipient. 为了简单起见,我在这里坚持 1:1 消息传递(与消息可能属于许多收件人的群聊相比)。

class Message
  belongs_to :recipient, class_name: 'User'
  belongs_to :sender, class_name: 'User'
end

class User
  has_many :sent_messages, 
           class_name: 'Message', 
           foreign_key: 'sender_id' 
  has_many :messages, foreign_key: 'recipient_id'
end

请注意,当不能从关联名称派生时,我们需要告诉 Rails 类和外键。

read您可能需要考虑使用枚举来表示消息的状态,而不是使用布尔字段。

枚举基本上是一个映射到符号列表的整数列。

class Message
  enum :status, [:unread, :read] 
  belongs_to :recipient, class_name: 'User'
  belongs_to :sender, class_name: 'User'
  belongs_to :conversation
end

枚举为您提供以下范围:

Message.unread
Message.read

和条件如:

message.unread?
message.read?

如果您想添加更多状态,例如:archieved或,它会变得非常简单:trashed

有了这个,你就不需要你的unread_messages_count怪物了。这将消耗大量内存,因为您从数据库中提取记录只是为了计算相关记录。

current_user.messages.unread.size

我们还应该正确定义用户和对话之间的关系:

class Conversation
  has_many :messages
  has_and_belongs_to_many :users
end

class Users
  # ..
  has_and_belongs_to_many :conversations
end

这个has_and_belongs_to_many关系会将用户和转换存储在users_conversations连接表中。您可以使用以下生成器来创建连接表迁移:

rails generate migration users_conversations

添加:

在您的视图中使用session[:user_id]是一种非常糟糕的代码气味。您在整个应用程序中紧密耦合您的身份验证逻辑。

而是创建一个助手:

class SessionsHelper
  def current_user
    @current_user ||= User.find(session[:user_id])
  end

  def user_signed_in?
     !current_user.nil?
  end 
end

应用程序的其他部分不应该知道您将当前用户存储在session[:user_id]仅仅存在一个current_user.

于 2015-06-20T13:02:50.613 回答