使用 find_by 加载 Ruby on Rails

Posted

技术标签:

【中文标题】使用 find_by 加载 Ruby on Rails【英文标题】:Ruby on Rails Eager loading with find_by 【发布时间】:2020-11-06 00:47:21 【问题描述】:

我尝试制作一个电影应用程序,并坚持使用 find_by 进行预加载。

我在下面的另一个 *** Q&A 中发现了一个类似的案例,但对于我的案例来说还不够。

Rails 5 Eager load and then find_by

我有 2 个连接表记录,WatchList(MoviesUser) 和 Rating。我无法使用“has_many :users, through: :ratings”来评分,因为已经存在 MoviesUser 关系。

class Movie < ApplicationRecord
  has_and_belongs_to_many :users
  has_many :ratings
end
class User < ApplicationRecord
  has_and_belongs_to_many :movies
  has_many :ratings
end
class MoviesUser < ApplicationRecord
  belongs_to :movie
  belongs_to :user
end
class Rating < ApplicationRecord
  belongs_to :movie
  belongs_to :user
end

如何避免 N+1 查询如下?

我发现“movie.users.find_by_id”已经在下面的代码中解决了(感谢前面提到的*** Q&A),但是我无法解决“movie.ratings.find_by_id”。

@movies = Movie.joins(:ratings).where(ratings: user_id: current_user.id).includes(:ratings).includes(:users)
@watchlist_addeds = 
@movie_rating_current_user = 

@movies.preload(:users).each do |movie|
    @watchlist_addeds[movie.id] = movie.users.find_by_id(current_user.id) ? true : false
    @movie_rating_current_user[movie.id] = movie.ratings.find_by(user_id: current_user.id).rating_value
end

如果我将此代码更改为如下所示,它似乎可以解决,但是当每部电影的评分数量荒谬时,我不确定这是否是正确的答案。

@movie_rating_current_user[movie.id] = movie.ratings.filter |rating| rating.user_id == current_user.id[0].rating_value

【问题讨论】:

@watchlist_addeds@movie_rating_current_user 集合的格式重要吗?你能描述一下你打算如何使用这些收藏吗?我看到了一些简化此代码的变体。 【参考方案1】:

您的电影查询中已经有一个 where 条件,该条件将删除所有不属于当前用户的评分。在每一个中,movie.ratings 将只包含属于当前用户的评分。

您应该可以直接调用first 而不是find_byfilter,尽管它会做同样的事情并且与您的过滤器解决方案一样快。

【讨论】:

以上是关于使用 find_by 加载 Ruby on Rails的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on rails 5.2 - 带有活动存储的背景图像

Ruby on Rails:如何使用迁移向现有列添加非空约束?

Ruby on Rails 应用程序的 OpenID 支持

Choosing web framework: ASP.NET MVC vs Django Python vs Ruby on Rails(转载)

为啥 Ruby on Rails 不使用 .includes() 加载我的关联对象?

在 DataTables 表加载 Ruby on Rails 时显示微调器