Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails paperclip and SVG images

model.rb:

has_attached_file :image validates_attachment :image, :content_type => { :content_type => ['image/svg+xml'] }

Results in: "Image has an extension that does not match its contents, is invalid, and is invalid"

When trying to attach an SVG file that is in fact valid.

Note, I've also tried the 'image/svg-xml' type with the same result

like image 907
Kabir Sarin Avatar asked Mar 28 '14 14:03

Kabir Sarin


2 Answers

The solution to this problem for me was to make sure that the contents of the SVG file start with this:

<?xml version="1.0" standalone="yes"?>

Under the hood, Paperclip uses the file command to make sure that the contents of the file match the name of the file. That check seems to want this declaration at the beginning of SVG files.

I find this to be unfortunate considering that a sample file from W3C doesn't even have it in there:

<svg id='svg1' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
  <circle r="32" cx="35" cy="65" fill="#F00" opacity="0.5"/>
  <circle r="32" cx="65" cy="65" fill="#0F0" opacity="0.5"/>
  <circle r="32" cx="50" cy="35" fill="#00F" opacity="0.5"/>
</svg>

I'm considering adding some logic in the model to add this to the beginning of the contents if it's not already there before it runs the check. Not sure if I should really do that though.

like image 196
Chris Peters Avatar answered Oct 27 '22 04:10

Chris Peters


As Chris Peters mentioned, under the hood the file command is being used to check the mime type. On my Ubuntu machine, PaperClip (at the application level) correctly identifies the mime type as 'image/svg+xml', but the system command file identifies the mime type as text/html. (You can test this by running file --mime-type your_file.svg).

One solution to this is to define a content-type mapping the accepts svgs with either image/svg+xml or text/html:

Paperclip.options[:content_type_mappings] = {
  svg: %w(image/svg+xml text/html)
}

This can be done in a PaperClip initializer, for example config/initializers/paperclip.rb in a Rails app.

Personally I feel like this is acceptable if you're taking user input from say an admin in a cms, because you can probably trust that they're not trying to get up to mischief. I'm not sure how safe this would be otherwise though.

like image 35
Erik Froese Avatar answered Oct 27 '22 02:10

Erik Froese