2011-05-16 16 views
5

Estoy usando CarrierWave en mi aplicación de muestra Rails 3. Quiero validar la carga ubicación remota por lo que no entiendo la excepción error estándar cuando un usuario envía una URL no válida, ya sea en blanco o no una imagen:¿Cómo lo hago: validación de ubicación remota con CarrierWave?

CarrierWave::DownloadError in ImageController#create 
trying to download a file which is not served over HTTP 

Ésta es mi modelo:

class Painting < ActiveRecord::Base 
    attr_accessible :gallery_id, :name, :image, :remote_image_url 
    belongs_to :gallery 
    mount_uploader :image, ImageUploader 

    validates :name,  :presence => true, 
          :length => { :minimum => 5, :maximum => 100 } 
    validates :image,  :presence => true 

end 

ésta es mi controlador:

class PaintingsController < ApplicationController 
    def new 
    @painting = Painting.new(:gallery_id => params[:gallery_id]) 
    end 

    def create 
    @painting = Painting.new(params[:painting]) 
    if @painting.save 
     flash[:notice] = "Successfully created painting." 
     redirect_to @painting.gallery 
    else 
     render :action => 'new' 
    end 
    end 

    def edit 
    @painting = Painting.find(params[:id]) 
    end 

    def update 
    @painting = Painting.find(params[:id]) 
    if @painting.update_attributes(params[:painting]) 
     flash[:notice] = "Successfully updated painting." 
     redirect_to @painting.gallery 
    else 
     render :action => 'edit' 
    end 
    end 

    def destroy 
    @painting = Painting.find(params[:id]) 
    @painting.destroy 
    flash[:notice] = "Successfully destroyed painting." 
    redirect_to @painting.gallery 
    end 
end 

no estoy muy seguro de cómo hacer frente a este problema de manera alguna idea sería grande.

+1

No estoy seguro de si la mejor manera de hacerlo es crear: valida: remote_image_url en el Modelo y tiene una expresión regular para validar si se trata de una URL y una imagen. –

Respuesta

0

La solución a este problema se ha agregado al CarrierWave Wiki en Github.

Editar:
Estoy tratando de poner en práctica la solución propuesta ahora, pero no puedo hacerlo funcionar. Estoy usando AR en Rails 3.1.3.

La implementación del código tal como está en la wiki da como resultado que la validación realmente suceda. Cuando intento subir un galimatías, recibo un buen mensaje de validación. El problema es que las cargas normales también se previenen.

+0

Esta solución no funciona para mongoid. Si alguien que trabaja con mongoid puede verificarlo, – hyperrjas

8

Me encontré con este mismo problema. Desafortunadamente, parece que este es un defecto de diseño de CarrierWave ... no permite la validación adecuada de una URL remota. CarrierWave intentará descargar el recurso de inmediato cuando se establezca el atributo y lanzará una excepción si la url no es válida, no se puede acceder, o si el recurso no tiene el tipo esperado. DownloadError o IntegrityErrors siempre se lanzan antes de que ocurra cualquier validación.

Por lo tanto, no pude encontrar una buena solución que utilice otros validadores. Mi solución terminó con este aspecto:

valid = false 
begin 
    par = params[:image].except(:remote_upload_url) 
    @image = Image.new(par) 
    # this may fail: 
    @image.remote_upload_url = params[:image][:remote_upload_url] 
    valid = true 
rescue CarrierWave::DownloadError 
    @image.errors.add(:remote_upload_url, "This url doesn't appear to be valid") 
rescue CarrierWave::IntegrityError 
    @image.errors.add(:remote_upload_url, "This url does not appear to point to a valid image") 
end 

# validate and save if no exceptions were thrown above 
if valid && @image.save 
    redirect_to(images_configure_path) 
else 
render :action => 'new' 
end 

básicamente, envuelvo el constructor en un bloque de rescate e inicialmente configurar todos los parámetros excepto por la URL remota. Cuando configuro eso, se puede producir una excepción que maneja al configurar manualmente un error en el modelo. Tenga en cuenta que no se realizan otras validaciones en este escenario. Es un truco, pero funcionó para mí.

Espero que esto pueda abordarse en una versión futura, retrasando la descarga del recurso hasta la etapa de validación del modelo o posterior.

1

Esto es un problema muy molesto. Hice el rescue_from en mi application_controller.rb por ahora y solo mensajes flash que indican el problema. Es lo mejor que se me ocurrió. No soy partidario de obstruir el controlador y tener que usar ese código duplicado si tiene múltiples modelos que necesitan esas validaciones.

rescue_from CarrierWave::DownloadError, :with => :carrierwave_download_error 
    rescue_from CarrierWave::IntegrityError, :with => :carrierwave_integrity_error 

    def carrierwave_download_error 
    flash[:error] = "There was an error trying to download that remote file for upload. Please try again or download to your computer first." 
    redirect_to :back 
    end 

    def carrierwave_integrity_error 
    flash[:error] = "There was an error with that remote file for upload. It seems it's not a valid file." 
    redirect_to :back 
    end 
0

La solución en la wiki de CarrierWave no me funciona. Como dijo Peter Hulst, CarrierWave carga el archivo antes de la validación. Encontré una forma de evitar esto capturando la excepción cuando se lanza y volviéndola a agregar como un error de validación más adelante. Por alguna razón, cuando se lanza una excepción, todos los atributos del otro registro se vuelven nulos, por lo que también deben capturarse y volver a agregarse antes de la validación. Este código todo va en su modelo.

Esto todavía necesita un poco de retrabajo para usar los mensajes de error de config, en lugar de hardcoded.

attr_accessor :additional_error_message, :original_attributes 

def initialize(*args) 
    self.original_attributes = args[0] 
    begin 
    super 
    rescue CarrierWave::IntegrityError # bad file type 
    self.additional_error_message = 'must be a PNG, JPEG, or GIF file' # depends on your whitelist 
    rescue OpenURI::HTTPError # 404 
    self.additional_error_message = 'could not be found' 
    rescue RuntimeError # redirection 
    self.additional_error_message = 'could not be loaded' 
    rescue CarrierWave::DownloadError 
    self.additional_error_message = 'could not be loaded' 
    rescue 
    self.additional_error_message = 'could not be loaded' 
    end 
end 

before_validation do |image| 
    if additional_error_message.present? 
    errors.add(remote_image_url, additional_error_message) 
    self.name = original_attributes[:name] # replace this with re-adding all of your original attributes other than the remote_image_url 
    end 
end 

# the image will have an "is blank" error, this removes that 
after_validation do |image| 
    errors.delete(:image) if additional_error_message.present? 
end 
Cuestiones relacionadas