1

我遇到了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

当我从控制台为条件为真的游戏运行它时(即game.home_team_score 大于game.away_team_score),如果一遍又一遍地运行相同的查询。

SELECT `games`.* FROM `games` WHERE `games`.`id` = 1 LIMIT 1

如果我为条件为假的 game_id 运行代码,则查找游戏的查询只发生一次,并且没有无限循环。

* 更新 *

我发现问题在于我从我的 GameObserver 调用该方法:

class GameObserver < ActiveRecord::Observer
  def after_save(game)
    Game.record_win_or_tie(game.id)
  end
end

但是,我不知道如何调整我的代码。要求是自动更新game.home_team_wongame.away_team_won在某人更新game.home_team_score或之后自动更新game.away_team_score

看来我不能使用观察者来做到这一点。

4

4 回答 4

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
于 2013-03-07T22:15:52.280 回答
3

会不会是你定义了一个 after_save 回调来再次调用 Game.record_win_or_tie?这将解释无限递归。

否则我们需要查看整个游戏模型

于 2013-03-07T22:13:02.973 回答
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
于 2013-03-07T22:44:29.993 回答
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 。

于 2013-03-07T23:59:03.247 回答