我有以下ActiveRecord模型:
class User < ApplicationRecord
has_many :user_alert_archives
end
class UserAlertArchive < ApplicationRecord
belongs_to :user
belongs_to :alert
end
class Alert < ApplicationRecord
has_many :user_alert_archives
end
当用户归档给定警报时,将使用该用户的ID和警报ID创建UserAlertArchive记录。对用户的归档警报运行查询非常简单。
Alert.joins(:user_alert_archives).where(user_alert_archives: {user_id: current_user.id})
它正在查询我遇到麻烦的那种情况的逆转。如何对不具有与当前用户ID相关联的UserAlertArchive的警报记录进行有效查询?
- 编辑 -
这有点难以解释,但这是我能够获得理想结果的唯一方式:
archived_ids = Alert.joins(:user_alert_archives).where(user_alert_archives: {user_id: current_user.id}).pluck(:id)
Alert.where.not(id: archived_ids)
这在技术上有效,但它会提取存档警报的所有ID,这对于拥有数千个警报的用户来说非常慢。如果可能的话,我希望能够在一个查询中完成它。
答案 0 :(得分:2)
使用Rails 5(方法'jeft_joins'退出)
Alert.left_joins(:user_alert_archives).where(user_alert_archives: {id: nil})
这将显示所有从未被任何人归档的警报。
如果您想要所有未由某个特定用户归档的警报,那么您可能需要添加一些sql:
Alert.where('id NOT IN (SELECT alert_id FROM user_alerts_archives u WHERE u.customer_id = ?)', current_user.id)
如果你有像UserAlert这样的模型,它持有警报状态(如'待定','已存档'),那么查询它们可能会更加美观和流畅。
答案 1 :(得分:0)
我喜欢M. Stavnycha使用子选择的方法,因此您不必将大量id
s传递给IN
子句。我建议将其放在Alert
的范围或类方法中。即。
class Alert < ApplicationRecord
has_many :alert_archives
def self.unviewed(user_id)
where("id NOT IN (SELECT alert_id FROM user_alert_archives WHERE user_id = ?)", user_id)
end
end