Rails - 获取包含无关联记录在内的许多关系的所有记录

问题描述 投票:0回答:2

我有以下几个有很多关系的课程。

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执行查询,所以我会为所有用户获取收藏夹(这有意义),但会过滤到当前用户。因此,我需要通过检查像movie.favourites.first这样的收藏夹并不理想 - 感觉有点奇怪。

有没有更好的查询我可以执行的地方,我可以在Favourite上执行搜索并获得用户还不喜欢的所有电影结果?或许还有别的东西。

我做了类似的事情

Favourite.includes(:movie)....

但我不确定如何为用户提供所有结果,包括非喜欢的电影结果。

ruby-on-rails ruby activerecord ruby-on-rails-5
2个回答
1
投票

您可以对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字段,指示特定电影是否受该用户的青睐。


1
投票

我会首先查询当前用户最喜欢的电影列表,并将他们的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的一个查询差。

© www.soinside.com 2019 - 2024. All rights reserved.