Rails4:如何验证carrierwave上传的图像大小?

时间:2014-10-08 13:01:37

标签: ruby-on-rails validation ruby-on-rails-4 carrierwave

我使用Rails4和Carrierwave上传文件,我让它正常工作。 我来看看下面这个aritcle 2. Model Level Validation

来检查图像大小

我在models \ article.rb中添加了validate :image_size_validation,但NoMethodError in ArticlesController#create已出现。

如何查看图像尺寸?

我应该使用file_size_validator.rb(请参阅How to: Validate attachment file size)而不是上述文章中的解决方案吗?

有什么想法吗?提前谢谢。

\模型\ article.rb

class Article < ActiveRecord::Base
...
    has_many :photos, dependent: :destroy
    validate :image_size_validation
...
    private

    def image_size_validation
        errors[:image] << "should be less than 1MB" if photos.image.size > 1.megabytes
    end

end

\模型\ photo.rb

class Photo < ActiveRecord::Base
    belongs_to :article
    mount_uploader :image, ImageUploader
end

\控制器\ article_controller.rb

...
  def create
    @article = current_user.articles.build(article_params)
    if @article.save
      flash[:success] = "article created!"
      redirect_to current_user #root_url
    else
        @article.build_images
       render 'new'
    end
  end
...

文章表

sqlite> .schema articles
CREATE TABLE "articles" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "content" varchar(255),"user_id" integer, "created_at" datetime, "updated_at" datetime, "category_id" integer);

照片表

sqlite> .schema photos
CREATE TABLE "photos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "article_id" integer,"image" varchar(255), "created_at" datetime, "updated_at" datetime, "bin_image" blob); #prepare bin_image for saving image as binary 

development.log

Started POST "/articles" for 127.0.0.1 at 2014-10-08 19:47:05 +0900
Processing by ArticlesController#create as HTML
  Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxx", "article"=>{"category_id"=>"1718", "photos_attributes"=>{"0"=>{"article_id"=>"", "image"=>#<ActionDispatch::Http::UploadedFile:0x4579140 @tempfile=#<File:C:/xxx/AppData/Local/Temp/RackMultipart20141008-5252-vsv6z>, @original_filename="DSCN0721_080.JPG", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"article[photos_attributes][0][image]\"; filename=\"DSCN0721_080.JPG\"\r\nContent-Type: image/jpeg\r\n">}, "1"=>{"article_id"=>""}, "2"=>{"article_id"=>""}}, "content"=>"test"}, "commit"=>"逋サ骭イ縺吶k"}
  [1m[35mUser Load (0.0ms)[0m  SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxx' LIMIT 1
  [1m[36m (0.0ms)[0m  [1mbegin transaction[0m
  [1m[35m (0.0ms)[0m  rollback transaction
Completed 500 Internal Server Error in 888ms

NoMethodError (undefined method `image' for #<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Photo:0x472f8d8>):
  app/models/article.rb:27:in `image_size_validation'
  app/controllers/articles_controller.rb:20:in `create'

修改

我在photo.rb中添加了image_size_validation而不是article.rb,但是当我上传超过1MB的图片时没有出现错误消息。

\模型\ photo.rb

class Photo < ActiveRecord::Base
    belongs_to :article
    mount_uploader :image, ImageUploader

validate :image_size_validation

    private

    def image_size_validation
        #errors[:image] << "should be less than xMB" if image.size > 1.megabytes
        #add the following code instead of above line
      if image.size > 1.megabytes
        errors.add(:base, "Image should be less than 1MB")
      end

    end

end

\ LOG \ development.log

Started POST "/articles" for 127.0.0.1 at 2014-10-11 05:50:06 +0900
Processing by ArticlesController#create as HTML
  Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxxx", "article"=>{"categort_id"=>"1718", "photos_attributes"=>{"0"=>{"article_id"=>"", "image"=>#<ActionDispatch::Http::UploadedFile:0x43af760 @tempfile=#<File:C:/xxxx/AppData/Local/Temp/xxxxk>, @original_filename="DSCN0721.JPG", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"article[photos_attributes][0][image]\"; filename=\"DSCN0721.JPG\"\r\nContent-Type: image/jpeg\r\n">}, "1"=>{"article_id"=>""}, "2"=>{"article_id"=>""}}, "content"=>"test"}, "commit"=>"逋サ骭イ縺吶k"}
  [1m[35mUser Load (0.0ms)[0m  SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
  [1m[36m (0.0ms)[0m  [1mbegin transaction[0m
  [1m[35mSQL (3.0ms)[0m  INSERT INTO "articles" ("content", "created_at", "category_id", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?)  [["content", "test"], ["created_at", Fri, 10 Oct 2014 20:50:08 UTC +00:00], ["category_id", 1718], ["updated_at", Fri, 10 Oct 2014 20:50:08 UTC +00:00], ["user_id", 1]]
Binary data inserted for `string` type on column `image`
  [1m[36mSQL (1.0ms)[0m  [1mINSERT INTO "photos" ("article_id", "created_at", "image", "updated_at") VALUES (?, ?, ?, ?)[0m  [["article_id", 78], ["created_at", Fri, 10 Oct 2014 20:50:08 UTC +00:00], ["image", "xxxx.jpg"], ["updated_at", Fri, 10 Oct 2014 20:50:08 UTC +00:00]]
  [1m[35m (3.0ms)[0m  commit transaction
Redirected to http://localhost:3000/users/1
Completed 302 Found in 1306ms (ActiveRecord: 7.0ms)

2 个答案:

答案 0 :(得分:7)

在你的照片模型中试试这个

validate :image_size_validation, :if => "image?"

def image_size_validation
    if image.size > 1.megabytes
      errors.add(:base, "Image should be less than 1MB")
    end
 end

删除private声明

答案 1 :(得分:4)

由于1.0版本CarrierWave具有内置文件大小验证。

安装最新的carrierwave gem

gem 'carrierwave', '~> 1.0'

添加方法size_range以提供最小尺寸和最大尺寸

class ImageUploader < CarrierWave::Uploader::Base
  def size_range
    0..2.megabytes
  end

在模型中添加validates_integrity_of以有效图像的文件大小(和内容类型)。

class Image < ApplicationRecord
  mount_uploader :image, ImageUploader

  validates_integrity_of :image

Rspec规范是:

it 'is invalid with an image size greater 2mb' do
  image = build(:image, image: File.open(File.join(Rails.root, 'spec/support/images/image-3mb.jpg')))
  image.valid?
  expect(image.errors[:image]).to include("File size should be less than 2097152")
end

要使错误消息更友好,请覆盖check_size!中的carrierwave ImageUploader方法。

 private
 def check_size!(new_file)
    size = new_file.size
    expected_size_range = size_range
    if expected_size_range.is_a?(::Range)
      if size < expected_size_range.min
        raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.min_size_error", :min_size => ApplicationController.helpers.number_to_human_size(expected_size_range.min))
      elsif size > expected_size_range.max
        raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.max_size_error", :max_size => ApplicationController.helpers.number_to_human_size(expected_size_range.max))
      end
    end
  end