What is the content type of json file to AWS S3 with ruby? - ruby-on-rails

I'd like to upload json file to S3 by ruby with paperclip. I coded as following, but it returned the following error.
undefined method `merge' for "application/json":String
Could you tell me how to set content-type of json-file?
product_definition.rb
class ProductDefinition < ActiveRecord::Base
belongs_to :product
has_attached_file :meta_data,
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:url => ":s3_domain_url",
:path => "/assets/:id/:style/:basename.:extension",
:s3_host_name => "s3-ap-northeast-1.amazonaws.com"
validates_attachment :meta_data, content_type: 'application/json'
end
products_controller.rb
#product_definition = ProductDefinition.create(meta_data:sample.json)

If you're using a recent version of Paperclip it looks like you formatted the arguments to validates_attachment_content_type incorrectly. I think it should be:
validates_attachment :meta_data, content_type: { content_type: 'application/json' }
See the example in the Paperclip Readme: https://github.com/thoughtbot/paperclip#validations
EDIT: How I came to this conclusion is by noticing the error says it tried to call merge on the string. Merge is meant to be called on a Hash, so therefore it expects a Hash value for :content_type.

What you have is exactly what the current docs on github state, but it does not work:
https://github.com/thoughtbot/paperclip
Other examples use a different way of formatting matching types - so very confusing.
What does seem to work, is a syntax-change which appears to date back years, which is:
validates_attachment :meta_data, attachment_content_type: {content_type: 'application/json'}
You can also put a set of acceptable content-types in an array, such as
validates_attachment :meta_data, attachment_content_type: {content_type: ['application/json', 'application/doc']}

Related

How does lambda function works in rails with an example from paperclip gem

I had a problem with the Paperclip gem where the default_url doesn't load after it fingerprinted in production environment, my code was like this:
class User
# Attachments to Paperclip - Profile pic
has_attached_file :profilepic_attachment,
:styles => {
thumb: '100x100#',
square: '500x500#'
},
:default_url => ActionController::Base.helpers.asset_path("missing/default_user.png"),
:preserve_files => true
validates_attachment_content_type :profilepic_attachment, content_type: /\Aimage\/.*\Z/
end
Note that when I do rails c in production and print out ActionController::Base.helpers.asset_path("missing/default_user.png"). The fingerprinted version (correct version) is printed out.
default_user-fb34158daae99f297ad672c43bb1a4d3917d8e272b5f2254aa055392aa2faa94.png.
However, when I inspect it from browser, the original /assets/missing/default_user.png appeared.
I struggled for long time until I came across this post, which tells me to change
:default_url => ActionController::Base.helpers.asset_path("missing/default_user.png"),
to
:default_url => lambda { |image| ActionController::Base.helpers.asset_path("missing/default_user.png") },
I wasn't sure what happened, but then it works. I then wonder what lambda function is for and when is it used in rails? also, it passed in a variable |image| but seems it wasn't use in the code. Why is that?
Thanks!

Getting Image Paperclip::Errors::NotIdentifiedByImageMagickError after updating to Paperclip 3.4.0

I got the following message after upgrading:
Paperclip 3.0 introduces a non-backward compatible change in your
attachment path. This will help to prevent attachment name clashes
when you have multiple attachments with the same name. If you didn't
alter your attachment's path and are using Paperclip's default, you'll
have to add :path and :url to your has_attached_file definition.
For example:
has_attached_file :avatar,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename"
So I did so:
post.rb:
has_attached_file :image, :styles => { :medium => "170x300>",
:thumb => "142x185>" },
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename"
But then I saw this error message:
Image Paperclip::Errors::NotIdentifiedByImageMagickError
I even added this to environments/development.rb:
Paperclip.options[:command_path] = "/usr/bin/"
(which identify outputs /usr/bin/identify)
But still no luck.
What could be the problem?
Wow, I didn't expect this. The problem wasn't due to upgrading.
It was because the file I was uploading was named like this:
Screenshot at 2012-11-26 16:22:44.png
Weird.
The issue is in the filename.
colons are not accepted, if you remove the colon from the attachment name using gsub it'll be accepted always.

setting content-type for mp4 files on s3

I am adding user uploaded videos to my RoRs site with the help of the paperclip gem and s3 storage. For some reason that I can't figure out, whenever a user uploads an mp4 file, s3 sets content-type for that file as application/mp4 instead of video/mp4.
Note that I have registered mp4 mime type in an initializer file:
Mime::Type.lookup_by_extension('mp4').to_s
=> "video/mp4"
Here is the relevant part of my Post model:
has_attached_file :video,
:storage => :s3,
:s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
:path => "/video/:id/:filename"
validates_attachment_content_type :video,
:content_type => ['video/mp4'],
:message => "Sorry, this site currently only supports MP4 video"
What am I missing in my paperclip and/or s3 set-up.
####Update#####
For some reason that is beyond my knowledge of Rails, my default mime types for mp4 contained files is the following:
MIME::Types.type_for("my_video.mp4").to_s
=> "[application/mp4, audio/mp4, video/mp4, video/vnd.objectvideo]"
So, when paperclip send an mp4 file to s3, it seems to identify the file's mime type as the first default, "application/mp4". That is why s3 identifies the file as having a content-type of "application/mp4". Because I want to enable streaming of these mp4 files, I need paperclip to identify the file as having a mime type of "video/mp4".
Is there a way to modify paperclip (maybe in a before_post_process filter) to allow for this, or is there a way to modify rails through an init file to identify mp4 files as being "video/mp4". If I could do either, which way is best.
Thanks for your help
Turns out that I needed to set a default s3 header content_type in the model. This isn't the best solution for me because at some point I might start allowing video containers other than mp4. But it gets me moving on to the next problem.
has_attached_file :video,
:storage => :s3,
:s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
:path => "/video/:id/:filename",
:s3_headers => { "Content-Type" => "video/mp4" }
I did the following:
...
MIN_VIDEO_SIZE = 0.megabytes
MAX_VIDEO_SIZE = 2048.megabytes
VALID_VIDEO_CONTENT_TYPES = ["video/mp4", /\Avideo/] # Note: The regular expression /\Avideo/ will match anything that starts with "video"
has_attached_file :video, {
url: BASE_URL,
path: "video/:id_partition/:filename"
}
validates_attachment :video,
size: { in: MIN_VIDEO_SIZE..MAX_VIDEO_SIZE },
content_type: { content_type: VALID_VIDEO_CONTENT_TYPES }
before_validation :validate_video_content_type, on: :create
before_post_process :validate_video_content_type
def validate_video_content_type
if video_content_type == "application/octet-stream"
# Finds the first match and returns it.
# Alternatively you could use the ".select" method instead which would find all mime types that match any of the VALID_VIDEO_CONTENT_TYPES
mime_type = MIME::Types.type_for(video_file_name).find do |type|
type.to_s.match Regexp.union(VALID_VIDEO_CONTENT_TYPES)
end
self.video_content_type = mime_type.to_s unless mime_type.blank?
end
end
...

Paperclip file name in validation message

Here is what I'm trying to do in the model:
has_attached_file :photo, :styles => self.image_sizes, :whiny => false
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'],
:message => I18n.t('paperclip.invalid_image_type', :file => self.photo.original_file_name)
I cant find the solution how should I get file name in original_file_name:
NameError (undefined local variable or method `photo_file_name' for #<Class:0xaafb004>):
or
NoMethodError (undefined method `photo' for #<Class:0xb303e7c>):
Problem is self is not the instance, but rather Class.
You can use the uploaded content-type as follows:
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'],
:message => :inclusion
and then in your translation file, add
activerecord.errors.models.<modelname>.attributes.photo.inclusion: "%{value} is not allowed"
where value will be replaced with the uploaded content type
Try photo_file_name instead of photo.original_file_name.
For more information on this, refer to Method: Paperclip::Attachment#original_filename
Hope it helps.
http://jimneath.org/2008/04/17/paperclip-attaching-files-in-rails.html
self.photo.url
Try using
self.photo.instance_read(:file_name)
For more information on Paperclip::Attachment#instance_read, refer to the docs here.
Hope this helps.

Ruby on Rails / Paperclip / AWS::S3::NoSuchBucket error

I installed the paperclip plugin and was able to use it locally. When I configured it to work with amazon S3 I keep getting the NoSuchBucket (The specified bucket does not exist) error. Paperclip documentation states that the bucket will be created if it doesn't exist but clearly
something is going wrong in my case.
I first insalled aws-s3 gem (v0.6.2)
then also installed right_aws gem (v1.9.0)
both have corresponding
config.gem "aws-s3", :lib => "aws/s3"
config.gem 'right_aws', :version => '1.9.0'
lines in environment.rb file
The code for the image.rb file with paperclip is as follows:
class Image < ActiveRecord::Base
belongs_to :work
has_attached_file :photo, :styles => {:big => "612x1224>", :small => "180X360>", :thumb => "36x36#"},
:storage => 's3',
:s3_credentials => YAML.load_file("#{RAILS_ROOT}/config/s3.yml")[RAILS_ENV],
:path => ":attachment/:id/:style/:basename.:extension",
:bucket => 'my-unique-image-bucket'
attr_protected :photo_file_name, :photo_content_type, :photo_size
validates_attachment_presence :photo
validates_attachment_size :photo, :less_than => 3.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png', 'image/gif']
end
I'm not entirely sure this is it, but your loading of the s3_credentials is different than what I'm using on my production sites.
My config line is:
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml"
Instead of
:s3_credentials => YAML.load_file("#{RAILS_ROOT}/config/s3.yml")[RAILS_ENV]
it should create but the bucket but this was a bug at one point :
http://groups.google.com/group/paperclip-plugin/browse_thread/thread/42f148cee71a0477
i recently had this problem and it turned out to be the servers time was hugely off and s3 wouldnt allow any updates "that far in the future" or similar but the rails error was NoSuchBucket...confusing
..
I have installed the s3fox plugin for firefox and created the bucket with the plugin. Now Paperclip works fine with S3 as the bucket identified is already created.
But I am still curious about paperclip's inability to create new buckets with the code above.
In case anyone winds up here via google: I saw this same error when I mistakenly switched the order of the 2nd and 3rd parameters I was passing to AWS::S3::S3Object.store.
It's not your case, but AWS doesn't allow upper case letters in bucket name and paperclip doesn't check that, failing in create_bucket.

Resources