简体   繁体   English

Ruby on Rails —堆栈级别太深

[英]Ruby on Rails — Stack level too deep

model: 模型:

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

Logs: 日志:

  (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'

And then it repeats the last line again and again until I stop it manually. 然后它一次又一次地重复最后一行,直到我手动停止它为止。 Can anyone tell me what I'm doing wrong? 谁能告诉我我在做什么错?

The reason for "stack level too deep error" is because you are calling update_attributes inside after_save callback, which will invoke the callback after_save again, calling update_attributes again, and so on... 之所以“堆栈级别太深错误”是因为你调用update_attributes里面after_save回调,这将调用回调after_save再次呼唤update_attributes再次,等等...

Change it to following: 将其更改为以下内容:

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

When you call update_attributes, the callbacks are called, as your method set_correct_post_type is set as "after_save", you end with an loop. 当您调用update_attributes时,将调用回调,因为您的方法set_correct_post_type设置为“ after_save”,因此以循环结尾。

You call save on you method that triggers the set_correct_post_type method that call update_attributes that triggers the set_correct_post_type method that call update_attributes... 您调用保存方法,该方法将触发调用update_attributes的set_correct_post_type方法,该方法将触发调用update_attributes的set_correct_post_type方法。

If you don't want to trigger the callbacks in your method, look at update_columns instead of update_attributes. 如果您不想在方法中触发回调,请查看update_columns而不是update_attributes。 Of consider setting attribute with a before_save instead of a after save. 考虑使用before_save而不是after保存来设置属性。

If you have your custom code, without any gems etc, avoid using rails callbacks. 如果您有自定义代码,没有任何gem等,请避免使用rails回调。 I'd recommend use Serice Object ex. 我建议使用Serice Object ex。 CreateTeacherPost which will create a post, do magic with params, types etc all in one Transaction. CreateTeacherPost可以创建一个帖子,在一个事务中使用参数,类型等进行魔术处理。 This way you will avoid problems like below and you will always know whats going on without callbacks magic. 这样,您将避免出现以下问题,并且您将始终知道发生了什么,而没有回调魔术。

But if you really want to use this pattern it's going into an infinite loop because each update_attributes is calling after_save! 但是,如果您真的想使用此模式,则会进入无限循环,因为每个update_attributes都调用after_save! callback method. 回调方法。 You could use update_column method or before_save callback and set attribute directly using self.post_type=number . 您可以使用update_column方法或before_save回调并直接使用self.post_type=number设置属性。 But first will call SQL update the second time, there is no reason to do this. 但是首先是第二次调用SQL update,所以没有理由这样做。

One more :) if you have to/want to use after callback better use after_commit callback. 还有一个:)如果您必须/想要在回调后使用,最好使用after_commit回调。 It's much safer. 更安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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