未读消息计数器

时间:2015-06-20 12:24:09

标签: mysql ruby-on-rails ruby-on-rails-4 private-pub

我正在rails 4上创建一个简单的聊天应用程序。创建了控制器,模型和视图,但功能仍然不完整。我的数据库,对话和消息中有2个表。会话表包含两个字段,发件人ID和接收者ID。消息表包含3个字段,正文,用户ID和读取(默认为0表示不读取)。

型号:

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

我想要做的是创建一个实时的功能,即每当有人收到新消息时接收未读消息。我正在使用私人酒吧来创建用户之间的聊天。

我有一个包含此功能的用户模型:

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

我有一个页面列出了所有用户的对话,并且单击了一个对话,所有与该对话相关的消息也被列出。在同一页面上,我订阅了每个conversation_messages_path,为每个会话创建单独的频道。每当发送消息时,都会呈现create.js.erb文件,我将其发布到那些订阅的频道:

<% 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 %>

$("#conversation_link")是我想要显示未读消息的地方。

目前,未读消息计数返回错误计数,导航栏仅在conversation.sender_id向接收方发送消息时更新。

我的未读邮件计数器未返回正确数量的未读邮件。我不知道如何解决它。我的代码有什么问题? 感谢。

1 个答案:

答案 0 :(得分:3)

我认为你的域建模真的没有了。

谈话的整个想法是有关各方轮流担任发件人和收件人。您的模拟是独白

  独白是一个人发表的讲话,或者是片面的长篇大论   谈话让你想要从乏味中拔出你的头发。   希腊词根monologos翻译为“独自说话”和   这是一个独白:一个人在做所有的谈话。

您最终使用的域名模型应如下所示:

database diagram

其实际链接到两个用户(或更多)的消息:senderrecipient。为了简单起见,我在这里坚持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类和外键。

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

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

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

Enums为您提供以下范围:

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