RAILS-获取所有记录都有许多通过关系,包括无关记录



我有以下类的班级有很多关系。

class Movie < ApplicationRecord
  has_many :favourites, dependent: :destroy
  has_many :users, through: :favourites
end
class Favourite < ApplicationRecord
  belongs_to :user
  belongs_to :movies
end

class User < ApplicationRecord
  has_many :favourites, dependent: :destroy
  has_many :movies, through: :favourites
end

我有一个搜索页面,允许用户按名称搜索电影。但是我还需要证明电影是否受到当前用户的喜爱。因此,基本上我有一个看起来像这样的查询(减少以保持相关性):

@movies = Movie.includes(favourites: :user)
               .where(favourites: { user: [current_user, nil] })

因此,在上面,我得到了所有电影,我也试图获得当前用户的所有收藏夹,但如果尚未获得电影的返回结果。

问题是,我现在必须检索用户喜欢的东西,例如:

@movies.each do |movie|
  movie.favourites.first # current users fav movie
end

因为我正在执行电影上的查询,所以我获得了所有用户的收藏集(有意义),但已过滤给当前用户。因此,我需要经过并检查movie.favourites.first之类的收藏夹并不理想。

感到有些奇怪。

我可以在Favourite上执行搜索并获得用户尚未获得的所有电影结果吗?也许还有其他东西。

我做过

之类的事情
Favourite.includes(:movie)....

,但我不确定如何获得所有结果,包括用户的非热门电影结果。

您可以使用left join

使用单个查询
res = Movie.left_joins(:favourites).where(fauvorites:{ user_id: [current_user.id, nil]}).
       select(Movie.arel_table[Arel.star], "(favourites.id is null) as is_favourited_by_user")
res.first.is_favourited_by_user # 0/1

返回的Movie对象将生成is_favorited_by_user字段,该字段指示该用户是否喜欢特定的电影。

我会首先查询当前用户喜欢的电影的列表,然后将其ID存储在Set中:

# in the controller
require `set`
@favorite_movies_ids = Set.new(Favourite.where(user: current_user).pluck(:movie_id))

使用这样的Set,如果当前用户喜欢特定的电影,则可以使用非常有效的O(1)操作来检查页面上的信息 - 例如:

# in the view
<% @movies.each do |movie| %>
  <%= 'favorite!' if @favorite_movies_ids.include?(movie.id) %>
  # ...
<% end %>

我想在这种情况下,两个简单的查询不会比一个复杂的JOIN在数据库中的一个查询差得多。

最新更新