How can I use Rspec to test that a model using Paperclip is validating the size of an uploaded file?
The best way I've done this is to use the built-in shoulda matchers for Paperclip. The documentation at that link is really good, but here's an overview from the docs of what you can do with it:
In spec_helper.rb, you'll need to require the matchers:
require "paperclip/matchers"
And include the module:Spec::Runner.configure do |config|
config.include Paperclip::Shoulda::Matchers
end
Example that validates the attachment size:describe User do
it { should validate_attachment_size(:avatar).
less_than(2.megabytes) }
end
If you're interested, the source for the matchers can be found on GitHub Unit testing paperclip uploads with Rspec (Rails)
This should work with Rails 2.X:
Image.new :photo => File.new(RAILS_ROOT + '/spec/fixtures/images/rails.png')
As of Rails 3, RAILS_ROOT
is no longer used, instead you should use Rails.root
.This should work with Rails 3:
Image.new :photo => File.new(Rails.root + 'spec/fixtures/images/rails.png')
Definitely get the RSpec book, it's fantastic. Rails: Testing file upload validation (Shrine gem) at model spec
I would recommend that you test metadata extraction and validation separately. The metadata extraction you need to test with real IOs, but for validation tests you can assign a cached file with the desired metadata which doesn't have to actually exist.
RSpec.describe ImageUploader do
def uploaded_file(metadata = {})
Shrine.uploaded_file(
"id" => "123",
"storage" => "cache",
"metadata" => {"mime_type" => "image/jpeg", "size" => 100}.merge(metadata)
)
end
let(:share_image) do
FactoryGirl.build(:share_image, image: uploaded_file(metadata).to_json)
end
let(:metadata) { Hash.new }
describe "validations" do
before(:each) { share_image.valid? }
context "when image is correct" do
it "passes" do
expect(share_image.errors).to be_empty
end
end
context "when extension is correct but MIME types isn't" do
let(:metadata) { Hash["filename" => "image.jpg", mime_type => "text/plain"] }
it "fails" do
expect(share_image.errors[:image].to_s).to include("isn't of allowed type")
end
end
context "when file is larger than 10MB" do
let(:metadata) { Hash["size" => 11 * 1024 * 1024] }
it "fails" do
expect(share_image.errors[:image].to_s).to include("too large")
end
end
end
end
Validate a model
If you are open for adding a new gem then I would highly recommend using popular Paperclip
gem which has built-in validations for file size
, content type/ extension
and presence
.
Refer to Paperclip Github Documentation.
It would be as simple as saying
validates_attachment :image, :presence => true,
:content_type => { :content_type => ["image/jpg", "image/jpeg", "image/gif", "image/png"] },
:size => { :in => 0..10.kilobytes }
For a model with field named image
(Paperclip attachment).Where:
:presence
Validates that a file was attached while form submission
:content_type
Validates file extensions(mime-type) specified. It will also check the actual content of the uploaded file. Read my findings here.
:size
Validates the uploaded file size against the given range.
Related Topics
Stripping Commas from Integers or Decimals in Rails
Completely Random Identifier of a Given Length
Sorting a Hash in Ruby Based on Value and Then Key
Recording Audio Through Rtmp/Rails
How to Flush HTML to The Wire in Sinatra
How to Add a User Interrupt to an Infinite Loop
Ruby Class#New - Why Is 'New' a Private Method
Proper Usage of Ruby Statement Modifiers
Creating a Ruby on Rails Environment on Windows, in a Vm Vagrant Box
Using Elasticsearch to Filter Through Tags with Whitespace
What's The Best Way to Extract Excel Cell Comments Using Perl or Ruby
Rails Parameters from Get/Post
How to Remove a Url's Trailing Slash in a Rails App? (In a Seo View)