使用 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_by
或filter
,尽管它会做同样的事情并且与您的过滤器解决方案一样快。
【讨论】:
以上是关于使用 find_by 加载 Ruby on Rails的主要内容,如果未能解决你的问题,请参考以下文章
Ruby on rails 5.2 - 带有活动存储的背景图像
Ruby on Rails:如何使用迁移向现有列添加非空约束?
Choosing web framework: ASP.NET MVC vs Django Python vs Ruby on Rails(转载)