Ruby on Rails——堆栈级别太深
Posted
技术标签:
【中文标题】Ruby on Rails——堆栈级别太深【英文标题】:Ruby on Rails -- Stack level too deep 【发布时间】:2018-07-02 10:18:43 【问题描述】:型号:
after_save :set_correct_post_type
def set_correct_post_type
if self.document.present?
if (find_mime_type(self.document.original_filename) == "application/vnd.openxmlformats-officedocument.presentationml.presentation") || (find_mime_type(self.document.original_filename) == "application/vnd.ms-powerpoint")
self.update_attributes(:post_type => 3)
elsif (find_mime_type(self.document.original_filename) == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) || (find_mime_type(self.document.original_filename) == "application/msword") || (find_mime_type(self.document.original_filename) == "application/pdf")
self.update_attributes(:post_type => 2)
elsif (MIME::Types.type_for(self.document.original_filename).first.content_type == "image/png") || (MIME::Types.type_for(self.document.original_filename).first.content_type =="image/jpeg") || (MIME::Types.type_for(self.document.original_filename).first.content_type == "image/jpg")
self.update_attributes(:post_type => 5)
end
end #line17
end
日志:
(0.3ms) rollback transaction
Completed 500 Internal Server Error in 1939ms (ActiveRecord: 37.5ms)
SystemStackError (stack level too deep):
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
app/models/teacher_post.rb:17:in `set_correct_post_type'
然后它一次又一次地重复最后一行,直到我手动停止它。谁能告诉我我做错了什么?
【问题讨论】:
哪一行在app/models/teacher_post.rb:17
?
@JagdeepSingh 我已经在模型代码中注释了第 17 行
【参考方案1】:
“堆栈级别太深错误”的原因是因为您在after_save
回调中调用update_attributes
,这将再次调用回调after_save
,再次调用update_attributes
,以此类推...
改成如下:
before_save :set_correct_post_type
def set_correct_post_type
if self.document.present?
if (find_mime_type(self.document.original_filename) == "application/vnd.openxmlformats-officedocument.presentationml.presentation") || (find_mime_type(self.document.original_filename) == "application/vnd.ms-powerpoint")
self.post_type = 3
elsif (find_mime_type(self.document.original_filename) == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) || (find_mime_type(self.document.original_filename) == "application/msword") || (find_mime_type(self.document.original_filename) == "application/pdf")
self.post_type = 2
elsif (MIME::Types.type_for(self.document.original_filename).first.content_type == "image/png") || (MIME::Types.type_for(self.document.original_filename).first.content_type =="image/jpeg") || (MIME::Types.type_for(self.document.original_filename).first.content_type == "image/jpg")
self.post_type = 5
end
end
end
【讨论】:
【参考方案2】:当您调用 update_attributes 时,会调用回调,因为您的方法 set_correct_post_type 设置为“after_save”,您会以循环结束。
您调用 save 方法触发 set_correct_post_type 方法调用 update_attributes 触发 set_correct_post_type 方法调用 update_attributes...
如果您不想在方法中触发回调,请查看 update_columns 而不是 update_attributes。 考虑使用 before_save 而不是 after save 设置属性。
【讨论】:
【参考方案3】:如果您有自定义代码,但没有任何 gem 等,请避免使用 rails 回调。我建议使用 Serice Object ex。 CreateTeacherPost
将创建一个帖子,在一个事务中使用参数、类型等进行魔术。这样你就可以避免像下面这样的问题,并且在没有回调魔法的情况下你将永远知道发生了什么。
但如果你真的想使用这种模式,它会进入一个无限循环,因为每个 update_attributes 都在调用 after_save!回调方法。您可以使用update_column
方法或before_save
回调并直接使用self.post_type=number
设置属性。
但是第一次会调用 SQL 更新第二次,没有理由这样做。
还有一个 :) 如果你必须/想要使用 after 回调,最好使用 after_commit 回调。它更安全。
【讨论】:
以上是关于Ruby on Rails——堆栈级别太深的主要内容,如果未能解决你的问题,请参考以下文章
如何在应用程序级别加密 ruby on rails 中的完整路由
如何在Ruby on Rails的应用程序级别添加toastr JS通知
SystemStackError - 堆栈级别太深;在 Rspec 测试中,使用acts_as_audited、Rspec、数据库清理器