所以我有以下范围来查找所有打开的门票:
scope :opened, -> { where(status: 'open') }
现在我知道我的活动记录has_many
消息:
has_many :messages, as: :commentable
但是现在,我如何链接范围查询以便通过open和messages count > 0
进行选择?
对ruby来说很新,想了解更多关于此事的信息!
答案 0 :(得分:1)
我添加counter_cache
列可评论。这样,当创建新消息时,它会更新计数,因此您可以查询where("count > 0")
。
如果您决定采用该路线,则必须创建迁移以添加messages_count
列并回填现有值,但这是干净的方法。有关counter_cache
的更多信息,请访问:http://guides.rubyonrails.org/association_basics.html(搜索页面' counter_cache')
答案 1 :(得分:1)
在SQL中,您可能会将其作为EXISTS
相关子查询实现,因此您可以从Ticket
到Message
进行半连接。
你可以在Rails中实现:
Ticket.where(Message.where("messages.ticket_id = tickets.id").exists)
它不是很漂亮,但性能非常高,同样......
Ticket.where.not(Message.where("messages.ticket_id = tickets.id").exists)
话虽如此,计数器缓存在扫描大量票证方面表现更好,但计数器缓存可能与实际数字不同步,并且如果他们不同步则提出警报的预定作业将是可取的。如果我只是想知道儿童记录是否存在,我不确定我会这样做 - 我可能会使用exists
编辑:
对于"必须由管理员"我赞成......
Ticket.where(
Message.
joins(:user).
merge(User.admins).
where("messages.commentable_id = tickets.id").
where(commentable_type: "Ticket").
exists
)
...以及用户中的范围,表明他们是管理员:
def self.admins
where(admin: true)
end
你也可以通过管理员封装"消息"在Message类中自己的范围内的需求,因此语法变为:
Ticket.where.not(
Message.
by_admin.
where("messages.commentable_id = tickets.id").
where(commentable_type: "Ticket").
exists
)
答案 2 :(得分:0)
Ticket.opened.left_outer_joins(:messages).where.not(messages: {id: nil})
答案 3 :(得分:0)
这不是什么红宝石,而是SQL。使用消息进行内部联接,这样您只能获得至少一条消息的票证。
Ticket.joins(
"INNER JOIN messages on messages.commentable_id = ticket.id
AND messages.commentable_type = 'Ticket'"
)
然后按tickets.id分组并应用您需要的其他范围,例如.where(status: 'open')