5

Rails 3 サンプル アプリで CarrierWave を使用しています。リモート ロケーションのアップロードを検証して、ユーザーが空白または画像ではない無効な 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

4 に答える 4

8

私はこの同じ問題に遭遇しました。残念ながら、これは 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 を除くすべてのパラメーターを設定します。それを設定すると、モデルに手動でエラーを設定して処理する例外が発生する場合があります。このシナリオでは、他の検証は実行されないことに注意してください。それはハックですが、私にとってはうまくいきました。

モデルの検証段階またはそれ以降までリソースのダウンロードを遅らせることで、将来のリリースでこれに対処できることを願っています。

于 2011-07-05T07:55:28.810 に答える
1

これは非常に厄介な問題です。私は今の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
于 2012-09-13T04:47:01.850 に答える
0

この問題の解決策は、GithubのCarrierWaveWikiに追加されました。

編集:
私は現在提案されたソリューションを実装しようとしていますが、それを機能させることができません。Rails3.1.3でARを使用しています。

ウィキにあるようにコードを実装すると、検証が実際に正常に行われます。ジブリッシュをアップロードしようとすると、素晴らしい検証メッセージが表示されます。問題は、通常のアップロードも妨げられることです。

于 2011-12-20T12:58:41.903 に答える
0

CarrierWave wiki の解決策がうまくいきません。Peter Hulst が述べたように、CarrierWave は検証前にファイルをロードします。スローされたときに例外をキャプチャし、後で検証エラーとして追加することで、これを回避する方法を見つけました。何らかの理由で例外がスローされると、他のすべてのレコードの属性が nil になるため、検証前にそれらもキャプチャして再度追加する必要があります。このコードはすべてモデルに入ります。

これには、ハードコーディングされたものではなく、config からのエラー メッセージを使用するための少しの手直しが必要です。

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
于 2012-12-16T17:51:52.490 に答える