简体   繁体   English

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

[英]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_wongame.away_team_won之后自动更新game.home_team_scoregame.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM