如何过滤我的数据库查询以不包含基于关联表的记录?

时间:2018-04-10 01:48:58

标签: ruby-on-rails

我有一个用户模型,其中用户评价其他用户。他们通过与称为评级的表的多对多关联来实现这一点,该表具有与user_id(用户上的多对多自联接)对应的rater_id和ratee_id字段。模型是:

# app/models/user.rb
has_many :ratings_as_rater, class_name: "Rating", foreign_key: "rater_id"
has_many :ratings_as_ratee, class_name: "Rating", foreign_key: "ratee_id"

# app/models/rating.rb
belongs_to :rater, class_name: "User"
belongs_to :ratee, class_name: "User"

评级表上有一个复合索引:

# db/schema.rb
create_table "ratings", force: :cascade do |t|
  t.integer "rater_id"
  t.integer "ratee_id"
  t.integer "rate" # Users rated on scale 1-4
  t.index ["ratee_id"], name: "index_ratings_on_ratee_id"
  t.index ["rater_id"], name: "index_ratings_on_rater_id"
  t.index ["rater_id", "ratee_id"], name: "index_ratings_on_rater_id_and_ratee_id", unique: true
end

在用户索引页面上,我只想显示current_user尚未评级的用户。所以在users_controller而不是:

def index
  @users = User.all
end

我如何只显示current_user尚未评级的用户? Current_user id存储在会话cookie中。

1 个答案:

答案 0 :(得分:1)

如果您设置了间接关联,那么它很直接:

class User < ApplicationRecord
  has_many :ratings_as_rater, class_name: "Rating", foreign_key: "rater_id"
  has_many :ratings_as_ratee, class_name: "Rating", foreign_key: "ratee_id"
  has_many :raters, through: :ratings_as_ratee,
                    source: :rater
  has_many :rated_users, through: :ratings_as_rater,
                    source: :ratee

  # class level scope to fetch users with no rating
  def self.unrated_users
    left_outer_joins(:ratings_as_rater).where(ratings: { id: nil })
  end

  # users not rated by this user
  def unrated_users
    self.class.where.not(id: self.rated_users)
  end
end

一个重要的性能方面是User.where.not(id: self.rated_users)而非User.where.not(id: self.rated_users.ids)。这使得ActiveRecord可以构造一个子选择,而不是将数据库中的id拉出到Ruby中,然后将它们放回到一个巨大的长查询中。