我有一个Rails应用程序,它包含一个TeamSeason
模型类。该类具有与Team
模型类的has_one
关联,以及与另一个称为opponents
的TeamSeason
的has_many
关联。我现在正试图编写一个方法,该方法传入一个Team
,并确定它的任何对手是否与该Team
关联。我写的方法看起来像这样:
def plays?(against_team)
total = opponents.count {|opponent| opponent.team == against_team}
return (total > 0)
end
count
方法应该计算使用指定的块I生成真值的数组元素的数量。但是,它似乎总是返回数组的完整长度。就好像我指定的块总是产生一个真值,不管怎样。
我添加了各种puts
调用,试图找出我的逻辑哪里出了问题。以下是我的观察结果:
当我在count方法旁边的块中添加任何
puts
调用时,我看不到这些语句的任何输出。块的内容似乎从未被执行当我使用对手数组的
each
方法和一个块插入一个额外的循环时,我可以打印我的数组对象的值,并确认它们的计算结果符合我的预期。我甚至可以puts
opponent.team == against_team
的值,并验证我编写的块在某些时候是否评估为false
,这是应该的。
我在这里错过了什么?
opponents
不是一个标准的ruby数组,它是一个ActiveRecord关联代理,对于某些方法表现不同。count
将在数据库中查询对手的数量,并且不会评估您正在通过的阻挡。做你想做的事情的一种更简单的方法是这样的:
def plays?(against_team)
opponents.joins(:team).where(teams: {id: against_team.id}).exists?
end
这将询问数据库你想要什么,并避免在你只检查特定比赛时加载所有对手。或者,您可以加载整个对手列表并使用any?
:
def plays?(against_team)
opponents.any?{|opponent| opponent.team == against_team.id}
end
请注意,这不仅会加载所有对手,还会一次加载每个对手的团队,从而导致N+1查询(这会导致性能问题)。您可以通过使用includes()
:加载相关团队来避免这种情况
opponents.includes(:team).any?{...}
您正在尝试的功能可以使用include?
方法来实现。
尝试:
def plays?(against_team)
opponents.collect(&:team).include?(against_team)
end