Rails ActiveRecord选择打开的门票&没有回复

时间:2017-10-27 14:32:36

标签: ruby-on-rails ruby activerecord

所以我有以下范围来查找所有打开的门票:

scope :opened, -> { where(status: 'open') }

现在我知道我的活动记录has_many消息:

 has_many :messages, as: :commentable

但是现在,我如何链接范围查询以便通过open和messages count > 0进行选择?

对ruby来说很新,想了解更多关于此事的信息!

4 个答案:

答案 0 :(得分:1)

我添加counter_cache列可评论。这样,当创建新消息时,它会更新计数,因此您可以查询where("count > 0")

如果您决定采用该路线,则必须创建迁移以添加messages_count列并回填现有值,但这是干净的方法。有关counter_cache的更多信息,请访问:http://guides.rubyonrails.org/association_basics.html(搜索页面' counter_cache')

答案 1 :(得分:1)

在SQL中,您可能会将其作为EXISTS相关子查询实现,因此您可以从TicketMessage进行半连接。

你可以在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')