Ruby on Rails - уровень стека слишком глубокий - PullRequest
0 голосов
/ 02 июля 2018

Модель:

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'

А потом снова и снова повторяет последнюю строку, пока я не остановлю ее вручную. Может кто-нибудь сказать мне, что я делаю не так?

Ответы [ 3 ]

0 голосов
/ 02 июля 2018

Когда вы вызываете update_attributes, вызываются обратные вызовы, так как ваш метод set_correct_post_type установлен как "after_save", вы заканчиваете циклом.

Вы вызываете метод save on you, который вызывает метод set_correct_post_type, который вызывает update_attributes, который запускает метод set_correct_post_type, который вызывает update_attributes ...

Если вы не хотите запускать обратные вызовы в вашем методе, посмотрите на update_columns вместо update_attributes. Рекомендуется установить атрибут с атрибутом before_save вместо последующего сохранения.

0 голосов
/ 02 июля 2018

Если у вас есть свой код, без каких-либо драгоценных камней и т. Д., Избегайте использования обратных вызовов rails. Я бы рекомендовал использовать Serice Object ex. CreateTeacherPost, который будет создавать посты, делать магию с параметрами, типами и т. Д. В одной транзакции. Таким образом, вы избежите проблем, как показано ниже, и вы всегда будете знать, что происходит без магии обратных вызовов.

Но если вы действительно хотите использовать этот шаблон, он входит в бесконечный цикл, потому что каждый update_attributes вызывает after_save! метод обратного вызова. Вы можете использовать update_column метод или before_save обратный вызов и установить атрибут напрямую, используя self.post_type=number. Но первый вызовет обновление SQL во второй раз, для этого нет никаких оснований.

Еще один :), если вы хотите / хотите использовать после обратного вызова, лучше использовать обратный вызов after_commit. Это намного безопаснее.

0 голосов
/ 02 июля 2018

Причина "слишком глубокой ошибки на уровне стека" заключается в том, что вы вызываете update_attributes внутри after_save обратного вызова, который снова вызывает обратный вызов 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
...