2016-11-07 5 views
1

루비 환경 : Ruby 2.3.1Rails 5.0.0.1입니다.Ruby on Rails로 텍스트 파일 가져 오기 트랜잭션에서 여러 예외를 처리하는 방법

많은 구매 항목을 가져올 텍스트 파일을 가져 오려고합니다. 구매 파일의

예 :

data.txt로

고객 \ tDescription \ TUNIT 가격 \ tQuantity \ tAddress \ tSupply 회사 \ n을 아토스 마태 복음 \ tChocolate \ T10의 \ T5의 \의 tSome 주소. \ t 초콜릿 회사 \ n

열은 탭 (\ t)으로 구분되며 마지막에 입력됩니다 (\ n).

모든 속성이 null 일 수없는 구매 클래스가 있습니다. 속성은 다음과 같습니다.

파일을 가져 오려면이 작업을 수행하고 코드를보다 깨끗하게 유지하려면 PurchaseImporter 클래스를 작성하기로 결정했습니다.

begin 
    ActiveRecord::Base.transaction do 
     purchase = Purchase.new 
     data = line.force_encoding('UTF-8').split(/\t/) 

     purchase.customer_name = data[0] 
     product = Product.find_or_create_by!(description: data[1], price: data[2]) 
     purchase.product_quantity = data[3] 
     purchase.product = product 
     supply_company = SupplyCompany.find_or_create_by!(name: data[5], address: data[4]) 
     purchase.supply_company = supply_company 

     purchase.save! 
    end 
    rescue Exception => e 
    @errors[:import][index] = e.message 
    end 

내 문제는 내가이 트랜잭션 내에서 일어날 수있는 제품, SupplyCompany 및 구매의 모든 제기 오류를 포착 할 것입니다 :

내 문제는 트랜잭션의 일부입니다.

이것은 설명하기 위해 불필요한 코드가없는 경우의 순서입니다.

product = Product.find_or_create_by!(description: data[1], price: data[2]) 
supply_company = SupplyCompany.find_or_create_by!(name: data[5], address: data[4]) 
purchase.save! 

나는 화면에서이 3 개 클래스에이 오류 정보를 인쇄해야하지만, 내 코드와 함께, 난 단지 제품에 의해 생성 된 첫 번째 예외 오류를 잡을 수 있습니다. SupplyCompany 또는 Purchase에서 오류가 발생하면 이러한 오류 메시지가 손실됩니다.

파일을 가져올 때 오류 메시지를 가져오고 기록하는 다른 방법이 있습니까?

답변

3

더 구체적인 예외 처리를 할 수 있습니다 ... 트랩하려는 각 섹션에 대한 복구를 수행하고, 이전 오류가 발생하면 오류를 발생시키고 (트랜잭션 블록에서 나갈 수 있도록) 테스트합니다. 그 마지막 오류는 당신이 자신의 raise을 구하고 있다는 것입니다. 그렇지 않으면 다른 문제가 발생하고 정지해야합니다.

begin  
    ActiveRecord::Base.transaction do 
    error_encountered = false 
    purchase = Purchase.new 
    data = line.force_encoding('UTF-8').split(/\t/) 
    purchase.customer_name = data[0] 
    begin  
     product = Product.find_or_create_by!(description: data[1], price: data[2]) 
     purchase.product_quantity = data[3] 
     purchase.product = product 
    rescue Exception => e 
     @errors[:import][index] = e.message 
     error_encountered = true 
    end 
    begin 
     supply_company = SupplyCompany.find_or_create_by!(name: data[5], address: data[4]) 
     purchase.supply_company = supply_company 
    rescue Exception => e 
     @errors[:import][index] = e.message 
     error_encountered = true 
    end 
    begin 
     purchase.save! 
    rescue Exception => e 
     @errors[:import][index] = e.message 
     error_encountered = true 
    end 
    raise 'break out of transaction' if error_encountered 
    end 
rescue Exception => e 
    raise unless e.message == 'break out of transaction' 
end 
+0

도움을 주셔서 감사합니다. 이 정보는 매우 유용했습니다. –

+0

도움이 되었기 때문에 기쁩니다. 투표를하지 못할 수도 있지만 문제가 해결되면 대답을 "수락"할 수 있습니다 (옵션이 문제의 왼쪽에 있습니다). 최대한 빨리 pleaner의 대답이나 내 대답을 받아 들일 수 있습니다. – SteveTurczyn

0

Exception을 구하고 있기 때문에 실제로 어떤 오류가 발생하는지 알기가 어렵습니다. 구할 때 가능하면 좀 더 구체적인 클래스를 사용해야합니다.

또한 rescue를 사용할 필요가 없을 수도 있습니다. 사용중인 활성 방법 : find_or_create_by!save!은 오류를 발생시키지 않도록 느낌표없이 쓸 수 있습니다.

활성 레코드에서 유효성 검사 오류로 무언가를 저장하려고 시도하면 <record>.errors.full_messages 배열이 채워집니다. 느낌표를 사용하지 않으면 오류가 발생하지 않을 수도 있습니다 (오류는 모든 종류의 문제에서 제기 될 수 있습니다).

그래서, 예를 들어, 당신은 시도하고 레코드를 저장하고이 같은 오류를 확인할 수 있습니다

product = Product.find_or_initialize_by(description: data[1], price: data[2]) 
    product.save 
    errors[:import][index] ||= [] 
    errors[:import][index].concat product.errors_full_messages 

사실,이 경우에 나는 당신의 접근 방식은 몇 가지 의미가 있습니다 생각합니다. 순서대로 몇 개의 레코드를 저장하고 있습니다. 첫 번째 오류가 발생하면 다른 오류가 발생할 수 있습니다. 따라서 후속 레코드를 저장하려고 시도 할 가치가 있습니까? 내가 결정하게 할께.

+0

안녕하십니까. 내 문제를 해결하는 것이 매우 유용했습니다. 오류가있는이 큰 배열을 만들었습니다. 죄송합니다. 투표 해 드릴 수 없습니다. 나는 여기에서 더 새로운 사람이다. –