2011-01-24 4 views
1

이전 코드 블록에서 오류가 발생하지 않는 경우에만 실행하고 싶은 코드 섹션이 있습니다. 해키처럼 보이는 솔루션을 구현했으며 Ruby에서 더 좋은 방법이 있다고 확신합니다.Refactor : 예외가 throw되지 않은 경우에만 코드 블록 실행

existing_comments = Comment.all 
catch(:creation_failure) do 
    begin 
     ActiveRecord::Base.transaction do 
      results.each do |row| 
       Comment.create!(row) 
      end 
     end 
    rescue 
     throw(:creation_failure) 
    end 
    existing_comments.destroy_all 
end 

있어 꼭이 작업을 수행 할 수있는 더 좋은 방법이 될 :

는 여기에 지금까지 무슨이다.

답변

0

봅니다 (I는하지 않았다 테스트 할 수있는 기회) :

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 
+0

이렇게하면 destroy_all 메서드의 예외도 무시됩니다. 질문 작성자가 원한다면 나는 모른다. – ehabkost

+1

시작할 수있는 구조 블록을 가지고있는 유효한 루비가 있습니까? – vrish88

+0

vrish88- 예, 할 수 있습니다 – jschorr

0

거래 - http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html은 - 블록이 원자 작업으로 실행되었는지 확인합니다. 예외가 발생하면 전체 트랜잭션이 롤백됩니다. do_something하지 않는 경우

def my_method 
    do_something 
    do_something_else 
end 

이 방법은, do_something_else 만 실행됩니다 : 당신의 질문을 읽을 때, 나는 "이 사소한 잠깐 : 당신은 항상처럼 당신의 코드를 작성"생각

+0

그는 이미 트랜잭션을 사용하고 있으며 예외가 발생하고 트랜잭션이 이미 중단 된 후에 추가 코드를 실행하지 않으려합니다. – ehabkost

-1

예를 들면, 예외를 발생시킵니다. 당신은 특별한 것을 할 필요가 없습니다.

그러나, 당신이 정말로 원하는 것은 바로, do_something_else이 do_something에 의해 제기 된 예외를 무시하고 실행하지 않는 것입니다처럼 보인다?

예외를 무시할 계획이라면 정말주의해야하지만 실제로 그렇게하고 싶다면 코드 블록에서 예외를 무시하고 다른 것을 실행하지 않는 쉬운 방법이 될 것입니다. 메서드에서 단순히 반환 할 수 있습니다. 이처럼 : 나는 코멘트가 정상에 파괴 이동 한

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

:

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

@ Jörg W Mittag 솔루션도 참조하십시오. "else"를 사용하는 것은 내가했던 것처럼 "return"을 사용하는 것보다 간단합니다. – ehabkost

1

나는이 리팩토링을 제안 할 것입니다. 완전히 똑같지는 않지만 (새로운 주석은 기존의 주석과 충돌하지 않을 것입니다.) 이것이 더 합리적이라고 생각합니다.

특정 시나리오에서 유용하므로 throw/catch은 정상적인 코딩에 사용하면 안되며 그렇지 않을 경우 스파이 젤리 코드가 끝나게됩니다. (rescue에 의해 처리) 상승 예외를 혼합 (catch 처리) 뭔가를 던져 코드에

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 

당신이 어려운 (나를 위해)합니다

0

나는 같은 것을 할 것입니다. 대부분의 시간은 raise 만 사용됩니다.

이론 : raise/rescue는 예외를 처리하는 데 사용되며 throw/catch는 흐름을 제어하는 ​​데 사용되며 예외가 아닌 모든 것을 throw 할 수 있습니다. 정말 필요한 경우가 아니라면 catch/throw를 피할 수 있습니다.

예외가 발생하면 흐름이 중단되므로 예외가 발생하지 않은 경우 해당 사실로부터 이익을 얻고 쉽게 처리 할 수 ​​있습니다.

희망이 도움이 :)

2

그것은 당신이하려고하는 것을 정확히 파악하는 것은 매우 어렵습니다. @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을 눈치 채지 못하게하는 것이 좋은 생각이라고 생각하십니까? ActiveRecordError이라는 39 개의 직접 하위 클래스가 있습니다. 그 중 하나가 모든 예외를 구하는 것보다 적합합니다 (또는 적어도 모두 StandardError 예외).

+0

BTW : 저는 pointfree 스타일의 팬입니다. 그래서 리터럴 블록 대신에'results.each (& Comment.method (: create!))'라고 쓰겠습니다. 나는 어쨌든 필요하지 않은 변수에 대한 이름을 발명하는 것을 좋아하지 않습니다. 이러한 변수를 단순히 가치가없는 수준으로 향상시킵니다. –

관련 문제