从回调方法堆栈太深

时间:2016-07-14 19:01:36

标签: ruby-on-rails ruby-on-rails-4

我有四种运动,金牌,银牌和铜牌的模特,运动与其他三种模式之间有一对一的关系。每一项运动都必须有金牌,银牌和铜牌;在Sports模型中使用回调函数创建三个。这些回调函数是一个抛出我能够跟踪的错误,因为轨道错误堆栈产生的只是一行。
 我的代码

模型

运动

class Sport < ActiveRecord::Base
    validates :sportname, presence: true, 
                         uniqueness: { case_sensitive: false }

   has_one :gold, inverse_of: :sport, :dependent => :destroy
   has_one :silver, inverse_of: :sport, :dependent => :destroy
   has_one :bronze, inverse_of: :sport, :dependent => :destroy

   accepts_nested_attributes_for :gold
   accepts_nested_attributes_for :silver
   accepts_nested_attributes_for :bronze


   after_validation :build_default_medals, on: :create

   def build_default_medals
    self.build_gold
    self.build_silver
    self.build_bronze
  end
end

class Gold < ActiveRecord::Base

  belongs_to :sport    #, inverse_of: :gold
  validates_associated :sport, presence: true

  belongs_to :team, inverse_of: :golds, counter_cache: true 
  validates_associated :team,  :if => :create, allow_nil: true  

  accepts_nested_attributes_for :team
  accepts_nested_attributes_for :sport
end

class Silver < ActiveRecord::Base

  belongs_to :sport   #, inverse_of: :silver   
  validates_associated :sport, presence: true

  belongs_to :team, inverse_of: :silvers, counter_cache: true 
  validates_associated :team, :if => :create, allow_nil: true    

  accepts_nested_attributes_for :team
  accepts_nested_attributes_for :sport
end

青铜

class Bronze < ActiveRecord::Base
  belongs_to :sport   #, inverse_of: :bronze
  validates_associated :sport, presence: true

  belongs_to :team, inverse_of: :bronzes, counter_cache: true 
  validates_associated :team,  :if => :create, allow_nil: true 

  accepts_nested_attributes_for :team
  accepts_nested_attributes_for :sport
 end

回调after_validation :build_default_medals, on: :create是错误所在,在我的日志

中生成此错误
 Started POST "/admin/sports" for 127.0.0.1 at 2016-07-14 14:52:22 -0400
 Processing by Admin::SportsController#create as HTML
 Parameters:{"utf8"=>"√",authenticity_token"=>"jss1O4bSJd3hcqxuSpu/KAxaowB7d
g5pLZw55oGDf1M=", "sport"=>{"sportname"=>"boxing"}, "commit"=>"Create Sport"}
User Load (1.0ms)  SELECT  `users`.* FROM `users`  WHERE `users`.`id` = 1       LIMIT 1  (0.0ms)  BEGIN
Sport Exists (1.0ms)  SELECT  1 AS one FROM `sports`  WHERE `sports`.`sportname` = 'boxing' LIMIT 1
SQL (1.0ms)  INSERT INTO `sports` (`created_at`, `sportname`, `updated_at`) VALUES ('2016-07-14 18:52:22', 'boxing', '2016-07-14 18:52:22')
SQL (15.1ms)  UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` = 13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms)  INSERT INTO `golds` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22')
SQL (1.0ms)  UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` =13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms)  INSERT INTO `silvers` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22')
SQL (1.0ms)  UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` =13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms)  INSERT INTO `bronzes` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22')  (72.2ms)  
ROLLBACK
Completed 500 Internal Server Error in 213ms

SystemStackError (stack level too deep):  actionpack (4.1.8) lib/action_dispatch/middleware/reloader.rb:79


Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_source.erb (2.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (4.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (7.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (145.1ms)

我很好奇为什么回调在插入后触发更新以及究竟是什么触发ROLLBACKStack Level Too Deep的无限循环。任何见解都表示赞赏。感谢。

修改

使用after_create :build_default_medals代替after_validation :build_default_medals, on: :creation生成

  Started POST "/admin/sports" for 127.0.0.1 at 2016-07-14 16:19:24 -0400
  Processing by Admin::SportsController#create as HTML
  Parameters: {"utf8"=>"√","authenticity_token"=>"3LrwB6+nD9PJ9EwxEgIGhN3rVHP3UPLOHUz9MXWRJ4Y=", "sport"=>{"sportname"=>"dancing"}, "commit"=>"Create Sport"}
  User Load (1.0ms)  SELECT  `users`.* FROM `users`  WHERE `users`.`id` = 1 LIMIT 1   (0.0ms)  BEGIN
  Sport Exists (1.0ms)  SELECT  1 AS one FROM `sports`  WHERE `sports`.`sportname` = 'dancing' LIMIT 1
  SQL (1.0ms)  INSERT INTO `sports` (`created_at`, `sportname`,`updated_at`) VALUES ('2016-07-14 20:19:24', 'dancing', '2016-07-14 20:19:24') 
 Gold Load (2.0ms)  SELECT  `golds`.* FROM `golds`  WHERE `golds`.`sport_id` =8 LIMIT 1
 Silver Load (1.0ms)  SELECT  `silvers`.* FROM `silvers`  WHERE `silvers`.`sport_id` = 8 LIMIT 1
 Bronze Load (1.0ms)  SELECT  `bronzes`.* FROM `bronzes`  WHERE `bronzes`.`sport_id` = 8 LIMIT 1
 (45.5ms)  COMMIT

编辑undefined method 'create' for #<Gold:0x63bf820>

def build_default_medals
  #Gold.create(sport: self, team: nil)
  #Silver.create(sport: self, team: nil)
  #Bronze.create(sport: self, team: nil)
  self.create_gold(team: nil)
  self.create_silver(team: nil)
  self.create_bronze(team: nil)
end

1 个答案:

答案 0 :(得分:0)

替换

after_validation :build_default_medals, on: :create

after_create :build_default_medals

你正在尝试建立相关模型,而体育仍然是一项新纪录,而不是一项坚持不懈的纪录。 validates_associated :sport, presence: true会导致循环依赖,并会出错。

我转载并测试了这一变化。它会正常工作。

对于保存的对象,请使用self.create_gold而不是self.build_gold,就像这样

  def build_default_medals
    self.create_gold
    self.create_silver
    self.create_bronze
  end

同时从Gold,Silver和Bronze模型中删除accepts_nested_attributes_for :sport。请参阅 - https://github.com/rails/rails/issues/7809