Rails范围/类方法,用于选择存在关联的项目

时间:2013-06-27 15:48:00

标签: ruby-on-rails ruby scope

似乎无法解决这个问题。我在下面有一个消息模型

Message
 # content:string
 # original_id:integer
 # sender_id:integer
 # receiver_id:integer

 has_one :reply, class_name: "Message", foreign_key: "original_id"
 belongs_to :original, class_name: "Message"

每条消息只能有一个回复,回复消息将有相应的原始消息。

我想要做的是创建一个范围或类方法,允许我在一个批处理中提取已回复的消息,在另一个批处理中提取未提取的消息。

这样的东西
 # return messages that have a reply present
 def self.replied
   where(reply.present?)
 end

 # return messages that have no reply
 def self.unreplied
   where(reply.nil?)
 end

所以我可以链接方法并最终用

拉取消息
 user1.messages.replied

它当前不起作用,因为我不能使用where子句,除非它是一个DB列...所以我考虑在DB中添加一个“replied”布尔列,所以我可以使用where子句但是有可能解决这个问题,我只是没想到。一个范围有一个lambda?我现在被困住了。

任何帮助非常感谢

1 个答案:

答案 0 :(得分:6)

要找到那些已经回复的内容相当简单:

scope :replied, joins(:reply)

任何没有回复的内容都会被INNER JOIN过滤掉。要找到那些没有回复的东西有点复杂 - 您可以使用LEFT JOIN或EXISTS子查询来完成此任务。 includes是一种强制LEFT JOIN的简单方法:

scope :unreplied, includes(:reply).
                  where(replies_messages: {id: nil}).
                  where(original_id: nil)

EXISTS子查询可能更有效,但写入更复杂(此时),因为它涉及调用Arel表(或Squeel)。对于大多数情况,LEFT JOIN将“足够好”,includes是一种快速而肮脏的方式来强制API使用它。