mysql - 未读消息计数器

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

<分区>

我正在 Rails 4 上创建一个简单的聊天应用程序。创建了 Controller 、模型和 View ,但功能仍然不完整。我的数据库中有 2 个表,对话和消息。 session 表包含两个字段,发送者 ID 和接收者 ID。 messages 表包含 3 个字段,body,user id 和 read(默认为 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

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

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

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 为每个对话创建单独的 channel 。每当发送消息时,都会呈现一个 create.js.erb 文件,我会在其中发布到那些订阅的 channel :

<% 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 消息接收方时更新。

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

最佳答案

我认为您的域建模确实有问题。

对话的整体理念是相关各方轮流担任发送者和接收者。你模仿的是独白

A monologue is a speech delivered by one person, or a long one-sided conversation that makes you want to pull your hair out from boredom. The Greek root word monologos translates to “speaking alone,” and that's a monologue: one person doing all the talking.

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

database diagram

它是实际上链接到两个用户(或更多)的消息:发件人收件人。为了简单起见,我在这里坚持使用 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 而不是 bool 型 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

我们还应该正确定义User和Conversation之间的关系:

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

添加:

在您的 View 中使用 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

关于mysql - 未读消息计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30953978/

相关文章:

ruby-on-rails - 如何在同一个 Rails Controller 操作中处理多个 HTTP 方法

php + mysql 行只返回 int

mysql - 改善 MySQL 慢查询

mysql - 使用 JOIN 返回错误删除多个表中的行

ruby-on-rails - Ruby on Rails : Notification System For Different Sets of Tags

ruby-on-rails - rails : constant in initializer

php - 在 float LARAVEL 上调用成员函数 addEagerConstraints()

ruby-on-rails - Rails 路由逻辑

javascript - 如何将变量从 Controller 传递到 application.js?

ruby-on-rails - 找不到类型为“application/javascript”的文件 'jquery-ui/datepicker'