我有四种运动,金牌,银牌和铜牌的模特,运动与其他三种模式之间有一对一的关系。每一项运动都必须有金牌,银牌和铜牌;在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)
我很好奇为什么回调在插入后触发更新以及究竟是什么触发ROLLBACK
和Stack 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
答案 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