Reputation: 93
I'm learning rails, and I've spent the last two days trying to figure out how to upload both video and images through the same model using paperclip. I feel like I've exhausted my resources in search of an answer, but haven't found anything that seems to help me apply the correct styles to the correct file type.
Here is my Image model (note: I started with an Image model and an avatar attribute. I am expanding it's use, so please don't get confused on how it's named)
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
has_attached_file :avatar,
if: :is_image_type?, styles: {:large => "750x750>", :medium => "300x300#", :thumb => "100x100#" }, :default_url => "no_image.png",
if: :is_video_type?, :styles => {
:medium => { :geometry => "640x480", :format => 'flv' },
:thumb => { :geometry => "100x100#", :format => 'jpg', :time => 10 }
}, :processors => [:transcoder]
validates_attachment_content_type :avatar,
:content_type => ['image/png', 'image/jpeg', 'image/jpg', 'image/gif', "video/mp4", "video/m4v", "video/mpeg"]
def is_image_type?
content_type = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif']
# /\Aimage\/.*\Z/
end
def is_video_type?
content_type = ["video/mp4", "video/m4v", "video/mpeg"]
end
end
Essentially I'm trying to figure out how to get the styles to work for their appropriate file types. If it is a video, I want it to be styled as a video, if it is an image, as an image.
The content validation is working fine, and I will alter it to include all image formats and all video formats once it is working.
Goal To summarize, my goal is to be able to have one file upload field where a user can upload multiple files and multiple file types including images, videos, audio, pdf, and other file types.
I will then use the "content_type" field to pull the file types I want to display on different areas of the site.
If this approach with one model seems inadequate, please indicate a better approach.
I'm using the 'paperclip-av-transcoder' gem to process video.
Again, I am learning rails, so if something is unclear I am happy to clarify and revise.
Thank you very much.
Upvotes: 3
Views: 2563
Reputation: 93
So I finally figured out the problem. My code was (basically) correct, though I'll past a final code here.
The problem was that it wasn't processing correctly because I didn't have an encoder installed on my machine.
So for anyone wanting to upload videos and is new like me, you'll want to install something like FFmpeg to take care of processing videos when they are uploaded.
I used homebrew with this tutorial and it was super easy: https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX
Here is the final version of my code:
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
# Apply styling appropriate for this file
has_attached_file :avatar, styles: lambda { |a| a.instance.check_file_type}, :default_url => "no_image.png"
validates_attachment_content_type :avatar, :content_type => /.*/
# The path of the image that will be shown while the file is loading
def processing_image_path(image_name)
"/assets/" + Rails.application.assets.find_asset(image_name).digest_path
end
process_in_background :avatar, processing_image_url: lambda { |a| a.instance.processing_image_path("dad.jpg")}
# IMPORTANT! The ffmpeg library has to added to the server machine.
# It can be uploaded from the official website https://www.ffmpeg.org/
def check_file_type
if is_image_type?
{:large => "750x750>", :medium => "300x300#", :thumb => "100x100#" }
elsif is_video_type?
{
:medium => { :geometry => "300x300#", :format => 'jpg'},
:video => {:geometry => "640x360#", :format => 'mp4', :processors => [:transcoder]}
}
elsif is_audio_type?
{
:audio => {
:format => "mp3", :processors => [:transcoder]
}
}
# avatar_file_name = self.basename(:avatar_file_name, self.extname(:avatar_file_name))
else
{}
end
end
# Method returns true if file's content type contains word 'image', overwise false
def is_image_type?
avatar_content_type =~ %r(image)
end
# Method returns true if file's content type contains word 'video', overwise false
def is_video_type?
avatar_content_type =~ %r(video)
end
# Method returns true if file's content type contains word 'audio', overwise false
def is_audio_type?
avatar_content_type =~ /\Aaudio\/.*\Z/
end
end
I'm still adding different data types and will specifically allow those data types to the validation when I'm complete, but this should show you what I did and you can build on it.
Hope this was helpful to someone else and not just me!
Upvotes: 4