我正在为我正在开发的rails应用程序组建一个消息传递系统。 我正在以与facebook系统类似的方式构建它,因此消息被分组为线程等。
我的相关模型是:
我的人际关系看起来像是
class User < ActiveRecord::Base
#stuff...
has_many :msg_threads, :foreign_key => 'originator_id' #threads the user has started
has_many :recipiences
has_many :subscribed_threads, :through => :recipiences, :source => :msg_thread #threads the user is subscribed to
end
class MsgThread < ActiveRecord::Base
has_many :messages
has_many :recipiences
belongs_to :originator, :class_name => "User", :foreign_key => "originator_id"
end
class Recipience < ActiveRecord::Base
belongs_to :user
belongs_to :msg_thread
end
class Message < ActiveRecord::Base
belongs_to :msg_thread
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
end
class Read < ActiveRecord::Base
belongs_to :user
belongs_to :message
end
我想在用户中创建一个新的选择器,如:
has_many :updated_threads, :through => :recipiencies, :source => :msg_thread, :conditions => {THREAD CONTAINS MESSAGES WHICH ARE UNREAD (have no 'read' models tying a user to a message)}
我正在考虑编写一个带有多个连接的长条件,或者可能写一个给模型一个updated_threads方法来返回它,但我想先看看是否有更简单的方法。我能够将某种嵌套哈希传递给条件而不是字符串吗?
有什么想法吗?此外,如果我的结构存在根本性的错误,请告诉我!谢谢!
更新
虽然如果它们存在,我仍然会欣赏更好的可能性,这就是我现在所做的工作:
class User < ActiveRecord::Base
# stuff...
def updated_threads
MsgThread.find_by_sql("
SELECT msg_threads.* FROM msg_threads
INNER JOIN messages ON messages.msg_thread_id = msg_threads.id
INNER JOIN recipiences ON recipiences.msg_thread_id = msg_threads.id
WHERE (SELECT COUNT(*) FROM `reads` WHERE reads.message_id = messages.id AND reads.user_id = #{self.id}) = 0
AND (SELECT COUNT(*) FROM recipiences WHERE recipiences.user_id = #{self.id} AND recipiences.msg_thread_id = msg_threads.id) > 0
")
end
end
似乎工作正常!
还要检查是否读取了特定的线程(和消息):
class Message < ActiveRecord::Base
# stuff...
def read?(user_id)
Read.exists?(:user_id => user_id, :message_id => self.id)
end
end
class MsgThread < ActiveRecord::Base
# stuff...
def updated?(user_id)
updated = false
self.messages.each { |m| updated = true if !m.read?(user_id) }
updated
end
end
有任何改善这方面的建议吗?
答案 0 :(得分:1)
您可能需要查看Arel,这有助于复杂的SQL查询。我相信(不要引用我)这已经融入了Rails3。
答案 1 :(得分:1)
将named_scope添加到MsgThread模型:
class MsgThread < ActiveRecord::Base
named_scope :unread_threads, lambda { |user|
{
:include => [{:messages=>[:reads]}, recipiencies],
:conditions => ["recipiences.user_id = ? AND reads.message_id IS NULL",
user.id],
:group => "msg_threads.id"
}}
end
注意: Rails使用:include
的LEFT OUTER JOIN。因此IS NULL
检查有效。
现在您可以执行以下操作:
MsgThread.unread_threads(current_user)
第二部分可以写成:
class Message
has_many :reads
def read?(usr)
reads.exists?(:user_id => usr.id)
end
end
class MsgThread < ActiveRecord::Base
def updated?(usr)
messages.first(:joins => :reads,
:conditions => ["reads.user_id = ? ", usr.id]
) != nil
end
end