[英]Rails Infinite Loop - Stack Level too Deep
I'm running into a stack level too deep
and have an infinite loop, but I can't figure out why, so I'm hoping someone else can spot it. 我遇到的stack level too deep
并且有无限循环,但是我不知道为什么,所以我希望其他人可以发现它。
I have this method in my Game model: 我的游戏模型中有以下方法:
def self.record_win_or_tie(game_id)
game = Game.find(game_id)
if game.home_team_score > game.away_team_score
game.home_team_won = true
game.save
end
end
When I run it from the console for a game where the conditional is true (ie game.home_team_score is greater than game.away_team_score) if keeps running the same query over and over again. 当我从控制台运行一个条件为true的游戏(即game.home_team_score大于game.away_team_score)时,如果不断重复运行相同的查询。
SELECT `games`.* FROM `games` WHERE `games`.`id` = 1 LIMIT 1
If I run the code for a game_id where the conditional is false, the query looking for the game only happens once and there is no infinite loop. 如果我在条件为false的情况下为game_id运行代码,则查找游戏的查询仅发生一次,并且没有无限循环。
* UPDATE * *更新*
I figured out that the problem was that I was calling the method from my GameObserver: 我发现问题出在我从GameObserver调用方法:
class GameObserver < ActiveRecord::Observer
def after_save(game)
Game.record_win_or_tie(game.id)
end
end
However, I don't know how to adjust my code. 但是,我不知道如何调整代码。 The requirement is to automatically update either game.home_team_won
or game.away_team_won
after someone has updated game.home_team_score
or game.away_team_score
. 要求是在有人更新了game.home_team_won
或game.away_team_won
之后自动更新game.home_team_score
或game.away_team_score
。
It seems like I can't use an observer to do this. 看来我无法使用观察者来执行此操作。
Use an instance variable to ensure it only gets saved once. 使用实例变量以确保仅保存一次。 However, because this is a class method, it will not be thread safe. 但是,因为这是一个类方法,所以它不是线程安全的。 Instead make this an instance method like so: 而是使它成为一个实例方法,如下所示:
def record_win_or_tie
return if @inside_callback
@inside_callback = true
if home_team_score > away_team_score
update_attributes(:home_team_won => true)
end
end
Now you can have your observer trigger the instance_method like this: 现在,您可以让观察者像这样触发instance_method:
class GameObserver < ActiveRecord::Observer
observe :game
def after_save(game)
game.record_win_or_tie
end
end
Note that you can also avoid all this if you perform this logic in a before_save
callback (without actually saving inside the callback) instead of after_save
: 请注意,如果您在before_save
回调中执行此逻辑(而不实际保存在回调内部),而不是after_save
,则也可以避免所有这些情况:
class Game < ActiveRecord::Base
def record_win_or_tie
self.home_team_won = true if home_team_score > away_team_score
end
end
class GameObserver < ActiveRecord::Observer
observe :game
def before_save(game)
game.record_win_or_tie
end
end
Could it be that you have defined an after_save callback that calls Game.record_win_or_tie again? 可能是因为您定义了一个after_save回调,该回调再次调用Game.record_win_or_tie? That would explain the infinite recursion. 那将解释无限递归。
Otherwise we'd need to see the entire Game model 否则,我们需要查看整个游戏模型
class Game < ActiveRecord::Base
# def self.record_win_or_tie(game_id) # deprecated
end
class GameObserver < ActiveRecord::Observer
def after_save(game)
if (game.home_team_score > game.away_team_score) && game.home_team_won != true
game.home_team_won = true
game.save
end
end
end
If for some reason it has to be in an after_save, instead of saving the current instance and triggering the after save, or adding spurious instance variables, call update on the db directly. 如果由于某种原因它必须在after_save中,而不是保存当前实例并触发after save或添加虚假实例变量,请直接在db上调用update。
if game.home_team_score > game.away_team_direct
Game.update_all({:home_team_won => true}, :id => id)
end
# Check the syntax, as I wrote it off the top of my head
But personally, if possible I'd move it to a before_save as mentioned in another answer. 但是就个人而言,如果可能的话,我会将其移至另一个答案中提到的before_save。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.