Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do :remote location validation with CarrierWave?

I'm using CarrierWave on my Rails 3 sample app. I want to validate the remote location upload so I don't get the standard error exception when a user submits an invalid URL either blank or not an image:

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

This is my model:

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

This is my controller:

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

I'm not really sure how to tackle this problem so any insight would be great.

like image 519
Wasabi Developer Avatar asked May 16 '11 02:05

Wasabi Developer


2 Answers

I ran into this same problem. Unfortunately it looks like this is a design flaw of CarrierWave... it does not allow for proper validation of a remote url. CarrierWave will attempt to download the resource right away when the attribute is set and will throw an exception if the url is invalid, can't be accessed, or if the resource doesn't have the expected type. DownloadError or IntegrityErrors are always thrown before any validation occurs.

Therefore I couldn't find a good workaround that uses other validators. My solution ended up looking like this:

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

basically, I wrap the constructor in a rescue block and initially set all parameters except for the remote url. When I set that, an exception may occur which I handle by manually setting an error in the model. Note that no other validations are performed in this scenario. It's a hack but worked for me.

I hope that this can be addressed in a future release, by delaying download of the resource until the model validation stage or after.

like image 105
Peter Hulst Avatar answered Nov 12 '22 04:11

Peter Hulst


This is very annoying issue. I did the rescue_from in my application_controller.rb for now and just flash messages stating the issue. It's about the best I could come up with. I am not a fan of clogging up the controller and having to use that duplicate code if you have multiple models that need those validations.

  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
like image 1
dft Avatar answered Nov 12 '22 04:11

dft