Как мне сделать: удаленная проверка местоположения с CarrierWave? - PullRequest
5 голосов
/ 16 мая 2011

Я использую CarrierWave в моем примере приложения Rails 3.Я хочу проверить загрузку удаленного местоположения, чтобы не получить стандартное исключение ошибки, когда пользователь отправляет недопустимый URL-адрес либо пустым, либо без изображения:

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

Это моя модель:

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

Это мой контроллер:

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

Я не совсем уверен, как решить эту проблему, так что любое понимание было бы здорово.

Ответы [ 4 ]

8 голосов
/ 05 июля 2011

Я столкнулся с этой же проблемой. К сожалению, похоже, что это конструктивный недостаток CarrierWave ... он не позволяет правильно проверить удаленный URL. CarrierWave попытается загрузить ресурс сразу же, когда атрибут будет установлен, и выдаст исключение, если URL недействителен, недоступен или если ресурс не имеет ожидаемого типа. DownloadError или IntegrityErrors всегда генерируются перед проверкой.

Поэтому я не смог найти хороший обходной путь, который бы использовал другие валидаторы. Мое решение в итоге выглядело так:

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

По сути, я обертываю конструктор в блоке восстановления и первоначально устанавливаю все параметры, кроме удаленного URL. Когда я устанавливаю это, может возникнуть исключение, которое я обрабатываю, вручную устанавливая ошибку в модели. Обратите внимание, что в этом сценарии другие проверки не выполняются. Это взлом, но работал для меня.

Я надеюсь, что это можно будет решить в следующем выпуске, отложив загрузку ресурса до этапа проверки модели или после него.

1 голос
/ 13 сентября 2012

Это очень раздражающий вопрос. Я сделал rescue_from в моем application_controller.rb на данный момент и просто прошил сообщения с сообщением о проблеме. Это лучшее из того, что я мог придумать. Я не фанат засорения контроллера и необходимости использовать этот дубликат кода, если у вас есть несколько моделей, которые нуждаются в этих проверках.

  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 голосов
/ 16 декабря 2012

Решение на вики CarrierWave не работает для меня.Как отметил Питер Хюлст, CarrierWave загружает файл перед проверкой.Я нашел способ обойти это, захватив исключение при его возникновении и добавив его обратно в качестве ошибки проверки позже.По какой-то причине, когда генерируется исключение, все атрибуты других записей становятся равными нулю, поэтому их также необходимо захватывать и повторно добавлять перед проверкой.Этот код все идет в вашей модели.

Это все еще требует небольшой переделки, чтобы использовать сообщения об ошибках из конфигурации, а не жестко закодировано.

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
0 голосов
/ 20 декабря 2011

Решение этой проблемы было добавлено в CarrierWave Wiki на Github.

Редактировать:
Я пытаюсь реализовать предложенное решениесейчас, но я не могу заставить его работать.Я использую AR на Rails 3.1.3.

Реализация кода в том виде, как он есть в вики, приводит к тому, что проверка действительно происходит нормально.Когда я пытаюсь загрузить бред, я получаю хорошее сообщение для проверки.Проблема в том, что обычные загрузки также запрещены.

...