2015-01-26 5 views
1

Amazon S3 버킷에서 가져온 Paperclip 이미지를 처리하기 위해 Delayed_Job을 사용하고 있습니다.레일 : 하나의 유효성 검사 오류에도 불구하고 다른 속성을 계속 저장합니다.

내가 해결하려고하는 기본 문제는 유효성 검사 오류가 Paperclip 이미지를 처리 ​​할 때 발생했을 때 DB에 저장할 수 있다는 것입니다.

내가 가진 기본적인 코드는 다음과 같다 :

class Provider < ActiveRecord::Base 

    after_save :queue_image_processing, if: Proc.new {|provider| provider.image_s3_key} 

    has_attached_file :image, styles: {original: "1000x1000", medium: "530x530#", thumb: "300x300#"}, default_url: "/default-avatar_:style.png" 

    validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/ 

    def self.process_image(id) 

     provider = Provider.find(id) 
     s3_image_object = S3_BUCKET.objects[provider.image_s3_key] 

     begin 
      provider.image = s3_image_object.public_url 
      provider.image_s3_key = nil 
      provider.image_started_processing_at = nil 
      provider.error = false 
      provider.save! 
     rescue ActiveRecord::RecordInvalid 
      logger.info "$$$$$ Record Invalid called $$$$" 
      provider.image_s3_key = nil 
      provider.image_started_processing_at = nil 
      provider.error = true 
      provider.save 
     end 
    end 

    private 

    def queue_image_processing 
     Provider.delay.process_image(id) 
    end 

최종 이미지가 올바른 형식이 아닌

(예를 들면 때문에 파일 확장자의 스푸핑의), 롤백이 수행되면, 구하다! throws :: RecordInvalid. 이것은 모두 좋으며 logger.info의 디버그 텍스트가 표시됩니다.

구조 문제의 나머지 코드는 수행되지 않는 것입니다 (예 : 이러한 속성이 DB에 저장되지 않음).

이 코드는 몇 가지 시도 중 하나 일 뿐이므로 기본 요구 사항은 DB에 유효성 검사 오류를받지 못한 다른 특성을 쓸 수 있어야합니다. 보시다시피, 나는 after_save 콜백을 가지고 있으므로이 콜백이 여러 번 호출되는 것을 피하기 위해 (그리고 콜백을 다시 실행하는 조건)주의해야합니다.

모든 도움을 주시면 감사하겠습니다. 덕분에 사전에

추신 :

+1

코드가 수행되지 않거나 레코드가 지속되지 않습니까? 레코드가 여전히 유효하지 않고'save'가 결과적으로 false를 반환한다는 것을 확인하는 것이 가치가 있습니다. – Shadwell

+0

네, 실제로 설명서와 예제 [here] (http://guides.rubyonrails.org/active_record_validations.html#errors-clear)를 읽은 후에 맞습니다. 코드가 실행됩니다 (구조 코드의 디버그 문자열이 표시되기 때문에이 사실을 알고 있습니다). 그러나 레코드는 여전히 유효하지 않습니다. 나는 유효성을 "재설정"하는 방법이 있는지 궁금해한다. (가이드는 분명히 내가 errors.clear를 사용할 수 없다고 말하고있다. 이것은 객체의 유효성을 바꾸지 않을 것이다.) ... – Andrea

답변

1

4.0 사실 내가 다윗 Verhasselt으로 Different ways to set attributes in Rails에 편리한 컨닝 페이퍼 덕분에 그것을 할 수있는 방법을 발견 레일.

그것은 가장 순수한 방법이 아닐지 모르지만, 작동합니다.

그것을 할 방법은 model.update_columns을 사용하는 것입니다

def self.process_image(id) 
    provider = Provider.find(id) 
    s3_image_object = S3_BUCKET.objects[provider.image_s3_key] 

    begin 
     provider.image_s3_key = nil 
     provider.image_started_processing_at = nil 
     provider.error = false 
     provider.image = s3_image_object.public_url 
     provider.save! 
    rescue ActiveRecord::RecordInvalid 
     logger.info "$$$$$ Record Invalid called $$$$" 
     provider.update_columns(image_s3_key: nil, image_started_processing_at: nil, error: true) 
    end 
end 

이 추가 혜택이있다 (내 경우에는, 그러나 모든 경우에 적합하지 않을 수 있습니다)에 updated_at이 이의를 업데이트하지입니다 유효성 검증은 수행되지 않고 콜백은 호출되지 않습니다. 내 경우에는 레코드가 사용자 작업 후에 업데이트되지 않고 오히려 실패로 인해 좋다.

다른 사람들에게 도움이되기를 바랍니다.