我遇到了stack level too deep
并且有一个无限循环,但我无法弄清楚为什么,所以我希望别人能发现它。
我的游戏模型中有这个方法:
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
当我从控制台运行条件为true的游戏时(例如game.home_team_score大于game.away_team_score)如果一遍又一遍地运行相同的查询。
SELECT `games`.* FROM `games` WHERE `games`.`id` = 1 LIMIT 1
如果我运行条件为false的game_id的代码,则查找游戏的查询只发生一次,并且没有无限循环。
*更新*
我发现问题在于我是从我的GameObserver调用方法:
class GameObserver < ActiveRecord::Observer
def after_save(game)
Game.record_win_or_tie(game.id)
end
end
但是,我不知道如何调整我的代码。要求是在有人更新game.home_team_won
或game.away_team_won
后自动更新game.home_team_score
或game.away_team_score
。
好像我不能用观察者来做这件事。
答案 0 :(得分:5)
使用实例变量确保它只保存一次。但是,因为这是一个类方法,所以它不是线程安全的。而是使这个实例方法如下:
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
现在你可以让你的观察者像这样触发instance_method:
class GameObserver < ActiveRecord::Observer
observe :game
def after_save(game)
game.record_win_or_tie
end
end
请注意,如果您在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
答案 1 :(得分:3)
你是否定义了一个再次调用Game.record_win_or_tie的after_save回调?这可以解释无限递归。
否则我们需要看到整个游戏模型
答案 2 :(得分:0)
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
答案 3 :(得分:0)
如果由于某种原因它必须在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
但就个人而言,如果可能的话,我会将其移至before_save,如另一个答案所述。