Rails无限循环 - 堆栈级别太深

yel*_*ign 1 ruby ruby-on-rails

我遇到了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
Run Code Online (Sandbox Code Playgroud)

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

SELECT `games`.* FROM `games` WHERE `games`.`id` = 1 LIMIT 1
Run Code Online (Sandbox Code Playgroud)

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

*更新*

我发现问题是我从GameObserver调用方法:

class GameObserver < ActiveRecord::Observer
  def after_save(game)
    Game.record_win_or_tie(game.id)
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,我不知道如何调整我的代码.要求是自动更新或者game.home_team_wongame.away_team_won有人更新后game.home_team_scoregame.away_team_score.

好像我不能用观察者来做这件事.

Pin*_*nyM 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
Run Code Online (Sandbox Code Playgroud)

现在你可以让你的观察者像这样触发instance_method:

class GameObserver < ActiveRecord::Observer
  observe :game

  def after_save(game)
    game.record_win_or_tie
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,如果在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
Run Code Online (Sandbox Code Playgroud)