如何在Rails控制器中从has_many through关联随机获取记录?
问题描述
我有一个能返回随机Recipe记录的Rails控制器方法:
@recipe = Recipe.order('RANDOM()').first
现在需要基于Recipe和Season的has_many through关联,返回属于指定season_id的随机Recipe记录。
模型关联定义如下:
Recipe模型:
class Recipe < ApplicationRecord attribute :name has_many :recipe_seasons has_many :seasons, through: :recipe_seasons end
Season模型:
class Season < ApplicationRecord has_many :recipe_seasons has_many :recipes, through: :recipe_seasons end
RecipeSeason模型:
class RecipeSeason < ApplicationRecord belongs_to :recipe belongs_to :season end
我当前的代码尝试:
@date = Time.now @month = @date.month @season = Season.find(@month) @recipe = Recipe.where(recipe_seasons: @month).order('RANDOM()').first
这段代码错误地返回了recipe_season_id等于@month的记录,而我需要的是season_id等于@month的随机Recipe记录。尝试了Recipe.where(recipe_seasons: season_id: @month)...也无效,求正确实现方式。
正确实现方式
方式一:通过关联表条件查询
使用嵌套哈希指定关联表的字段条件,同时必须通过joins关联中间表,让Rails正确识别关联字段:
@date = Time.now @month = @date.month @recipe = Recipe.joins(:recipe_seasons) .where(recipe_seasons: { season_id: @month }) .order('RANDOM()') .first
方式二:通过Season关联直接获取
既然已经查询到目标Season记录,可直接从其关联的recipes集合中取随机记录,写法更符合Rails关联语义:
@date = Time.now @month = @date.month @season = Season.find(@month) @recipe = @season.recipes.order('RANDOM()').first
方式三:跨数据库兼容的随机查询(Rails 6+)
如果使用Rails 6及以上版本,可使用order(:random)或Arel.sql('random()')替代原生SQL,提升跨数据库兼容性:
# 对应方式一的升级写法 @recipe = Recipe.joins(:recipe_seasons) .where(recipe_seasons: { season_id: @month }) .order(:random) .first # 对应方式二的升级写法 @recipe = @season.recipes.order(:random).first
内容的提问来源于stack exchange,提问作者cinameng
相关产品推荐
相关产品推荐

