3
votes

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.

1

1 Answers

4
votes

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!