Рефакторинг: Выполнение блока кода только в том случае, если не сгенерировано исключение - PullRequest
1 голос
/ 24 января 2011

У меня есть фрагмент кода, который я хотел бы запустить, только если предыдущий блок кода не выдает ошибку.Я реализовал решение, которое кажется хакерским, и я уверен, что есть лучший способ сделать это на Ruby.лучший способ сделать это.

Ответы [ 6 ]

2 голосов
/ 24 января 2011

Очень трудно понять, что именно вы пытаетесь сделать. Как уже указывал @ehabkost, если возникает исключение, выполнение в любом случае прерывается, поэтому вам ничего не нужно делать. Все, что идет после кода, вызвавшего исключение, все равно не будет выполнено, ведь это целая точка исключений.

Делает ли это то, что вы хотите?

existing_comments = Comment.all
begin
  ActiveRecord::Base.transaction do
    results.each do |row|
      Comment.create!(row)
    end
  end
rescue # You should *never* do this!
else
  existing_comments.destroy_all
end

Кстати: вы не должны никогда , ни при каких обстоятельствах, просто слепо спасать все исключения. Вы должны когда-либо спасать точно тех, кого вы ожидаете. Вы действительно думаете, что будет хорошей идеей просто слепо проглотить, скажем, ThreadError, даже не заметив этого? Существует только 39 прямых подклассов ActiveRecordError, возможно, один из них более уместен, чем просто спасение всех исключений (или, по крайней мере, всех StandardError исключений).

1 голос
/ 24 января 2011

Я бы предложил этот рефакторинг:

Comment.transaction do
  Comment.destroy_all
  results.each do |row| 
    comment = Comment.new(row)
    raise ActiveRecord::Rollback unless comment.save 
  end
end

Я переместил комментарии уничтожить наверх. Хотя это не совсем то же самое (новые комментарии теперь не будут противоречить существующим), я думаю, что это имеет больше смысла.

Обратите внимание, что throw/catch - как бы они ни использовались в определенных сценариях - не следует использовать в обычном кодировании, иначе вы получите неразрывный код спагетти.

0 голосов
/ 24 января 2011

Я бы сделал что-то вроде этого:

existing_comments = Comment.all
begin
  ActiveRecord::Base.transaction do
    results.each do |row|
      Comment.create!(row)
    end
  end
  existing_comments.destroy_all
rescue Exception => e
  # do something with the exception??
end

В своем коде вы усложняете (для меня) смешивание повышений исключений (обрабатывается rescue) и бросания чего-либо (обрабатывается catch).В большинстве случаев используется только raise.

Теория: повышение / спасение используется для обработки исключений, бросок / ловля используется для управления потоком, и вы можете бросать все что угодно (не только исключения).Если бы действительно не нужно, я бы избегал ловить / бросать.

Поскольку, когда возникает исключение, поток прерывается, мы можем легко извлечь выгоду из этого факта и делать вещи только в том случае, если исключение не произошло.

Надеюсь, это поможет:)

0 голосов
/ 24 января 2011

Когда я прочитал ваш вопрос, я подумал: «Подождите, это тривиально: просто напишите свой код, как вы всегда делаете», например ::

def my_method
  do_something
  do_something_else
end

Таким образом, do_something_else будет работать, только если do_something не вызовет исключение. Вам не нужно делать ничего особенного для этого.

Однако похоже, что вы действительно хотите не запускать do_something_else и игнорировать исключение, вызванное do_something, верно?

Я должен отметить, что вам следует быть очень осторожным, если вы планируете игнорировать исключения, но если вы действительно хотите это сделать, простой способ игнорировать исключение из блока кода и не запускать что-либо еще - просто вернитесь из метода. Как это:

def my_method
    existing_comments = Comment.all
    begin
        ActiveRecord::Base.transaction do
            results.each do |row|
                Comment.create!(row)
            end
        end
    rescue
        # just return. ignore any exceptions from the block above
        return
    end
    # this will run only if the above doesn't raise any exception:
    existing_comments.destroy_all
end
0 голосов
/ 24 января 2011

Транзакции - http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html - убедитесь, что блок выполняется как атомарное действие. При возникновении исключения выполняется откат всей транзакции.

0 голосов
/ 24 января 2011

Попробуйте (у меня не было возможности проверить это):

existing_comments = Comment.all
rescue Exception => e do 
  ActiveRecord::Base.transaction do
    results.each do |row|
      Comment.create!(row)
    end
    #you can log the failure messages, etc… by doing something with e
    existing_comments.destroy_all
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...