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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With