Implement video or image uploads with FFMPEG using carrierWave and heroku in rails 7

Implement video or image uploads with FFMPEG using carrierWave and heroku in rails 7

Dhaval Baldha

11 Sep 2023

10 MINUTES READ

Introduction

My latest blog explores my personal journey of grappling with Heroku server issues, shedding light on the invaluable lesson I learned while troubleshooting in the digital wilderness.

In this guide, we will explore how to set up video and image uploads, along with thumbnail generation in the Ruby on Rails 7 application. We'll use CarrierWave gem for file handling, FFMPEG for video processing, and deploy the application on Heroku, Follow these steps to enhance your Rails app with this powerful functionality.

Prerequisites: Before you begin, ensure you have the following in place:

  • Ruby on Rails environment
  • Bundler for gem management
  • An account for cloud storage (e.g. AWS, Azure, DigitalOcean)
  • FFMPEG is installed on your local system.
  • Access to Heroku account.

Add it to your gemfile


    gem 'carrierwave'
    gem "fog-aws"
    gem 'streamio-ffmpeg'
    gem "mini_magick"
    gem 'dotenv-rails', '2.7.6'
    

Execute the command bundle install

Restart the Rails server.

CarrierWave configuration

Execute the rails generate uploader Media

carrierwave configuration

In ‘MediaUploader’:


    class MediaUploader < CarrierWave::Uploader::Base
      #Storage file that you want to use
      if Rails.env.development?
        storage :file
      else
        storage :fog
      end
        
      def store_dir
        "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
      end
    end
    

The MediaUploder class is used for uploading files in the Rails application. It determines whether to store files locally or on cloud storage based on the environment.

The store_dir method in the CarrieWave uploader class is specific to the directory structure where uploaded files are stored. It combines information like the model’s class, the mounted uploader’s name, and the model’s ID to create an organised storage path.

Here is an example:

uploads/snap_datum/(mounted_as)/(model_id)

outcome: uploads/snap_datum/photo/38

Remember if storage :fog then you need to use your bucket credentials

In config/initializers/carrierwave.rb:

CarrierWave.rb

    require 'carrierwave/storage/fog'
    CarrierWave.configure do |config|
      config.fog_provider = 'fog/aws'             # Use Fog for AWS compatibility
      config.fog_credentials = {
        provider:              'AWS',
        aws_access_key_id:     ENV['AWS_ACCESS_KEY_ID'],       # Your AWS access key
        aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],   # Your AWS secret access key
        region:                ENV['AWS_REGION'],              # The region of your Spaces bucket
        endpoint:             ENV['AWS_ENDPOINT'] # The endpoint URL of your Spaces bucket
      }
      config.fog_directory  =  ENV['AWS_BUCKET']  # The name of your Spaces bucket 
      config.fog_public     = true               # Set to true if you want to make uploaded files publicly accessible 
      config.storage        = :fog               # Use fog storage 
    end
    

Requiring carrierwave/storage/fog' is necessary when you want to use CarrierWave with the “fog” storage provider for cloud storage.

After requiring the fog storage module, CarrierWave used specific storage services like Amazon S3, Google Cloud, and DigitalOcean.

The CarrierWave.rb configuration is set to set up file storage settings for uploading files to the cloud storage using the CarrierWave in Rails application. It configures the usage of AWS S3-compatible cloud storage(space) using the Fog gem. It includes AWS credentials, region, endpoint, and bucket information. Select the :fog storage option for Carrierwave to use cloud storage for file uploads.

Install gem 'dotenv-rails' #Loads environment variables from `.env`.

FFMPEG setup

Ensure FFMPEG is installed in your local system.


sudo apt-get install ffmpeg
Check this ffmpeg -v and which ffmpeg

ffmpeg setup

For Heroku, create a ‘buildpacks’ file with the following content. The root folder of your project dir creates a buildpacks file (project_name)/.buildpacks

In buildpacks file

In buildpacks file

heroku-buildpack-ffmpeg-latest

heroku-buildpack-ruby

Thumbnail generation


    require 'streamio-ffmpeg' #Load this top of the file 
    class MediaUploader < CarrierWave::Uploader::Base
      include CarrierWave::MiniMagick
      
      #Storage file that you want to be used.
      if Rails.env.development?
        storage :file
      else
        storage :fog
      end

      #Directory where the uploaded files are stored and you can customize the store_dir method part as needed.
      def store_dir
        "uploads/snap_datum/#{model.id}"
      end
        
      # Add an allowlist of extensions that are allowed to be uploaded.
      def extension_allowlist
        %w(jpg jpeg png mp4 mov)
      end
        
      #Create different versions of your uploaded files:
      version :thumb do
        process resize_to_fit: [50, 50]
      end

      version :thumb do
        process :genrate_thumb
        def full_filename (for_file = model.path.file) #The path is the field name of my model.
          "#{File.basename(for_file, '.*')}.jpg"
        end
      end

      def genrate_thumb
        tmpfile = File.join(File.dirname(current_path), "tmpfile")
        File.rename(current_path, tmpfile)

        begin
          movie = FFMPEG::Movie.new(tmpfile)
          new_filename = "#{current_path.chomp(File.extname(current_path))}.jpg"
          movie.screenshot(new_filename, { resolution: '320x240' },  seek_time: 2)
          file.content_type = 'image/jpg'
          File.rename(new_filename, current_path)

          File.delete(tmpfile)
          puts "Screenshot successfully generated!"
        rescue FFMPEG::Error => e
          puts "Error generating screenshot: #{e.message}"
          File.rename(tmpfile, current_path)
        rescue StandardError => e
          puts "Unexpected error: #{e.message}"
          File.rename(tmpfile, current_path)
        end
      end
    end
  1. version :thumb do: This defines a version named :thumb for the uploaded file
  2. process :genrate_thumb: This indicates that the :genrate_thumb method will be used to process the :thumb version of the uploaded file.
  3. Inside the :genrate_thumb method:
    • A temporary filename (tmpfile) is generated by joining the directory name of the current_path (original uploaded file) with the string "tmpfile".
    • The current_path is renamed to tmpfile, effectively moving the original uploaded file to the temporary location.
  4. A begin block starts the error handling.
    • An FFMPEG::Movie object is created using the tmpfile as the source.
    • A new filename (new_filename) is generated by removing the extension of current_path and appending ".jpg".
    • A screenshot is generated from the movie with specified options like resolution and seek time, and saved as new_filename.
    • The file's content type is set to 'image/jpg'.
    • The new_filename is renamed to the current_path, replacing the original uploaded file with the generated screenshot.
    • The tmpfile is deleted.
  5. Error handling:
    • If an FFMPEG::Error occurs during the process, an error message is printed, and the tmpfile is renamed back to current_path.
    • If any other standard error occurs, an unexpected error message is printed, and again, the tmpfile is renamed back to current_path.

Database changes

Create a migration to add ‘path’ field to your model:


    rails g migration PathFieldToSnapDatum path:string
    rails db:migrate

In your model(‘snap.rb’):


    class SnapDatum < ApplicationRecord
      mount_uploader :path, MediaUploader
    end

Controller and views

Modify your controller to handle file uploads, and create the from in your views.


    def create
      snap_data = SnapDatum.new
      snap_data.path = params[:file]
      snap_data.save
    end
    
In your view
<%= form.file_field :path %>

Testing and usage

You can now use the uploaded files and thumb in your application:

Rails console:
Rails console
Rails console
Rails console

Conclusion

Congratulations! 🎉 You’ve successfully implemented video and image uploads with thumb CarrieWave, FFMPEG, and Heroku in your rails application. This powerful combination allows you to manage and process media files. Explore further customization options and adapt this guide to your specific needs. By integrating Thumb carrierwave you’ve gained Ability to easily handle image and video uploads, making your rails application more versatile And user-friendly. Deploying your application on Heroku allows you to take advantage of scalable cloud infrastructure ensuring that your media processing capabilities can handle increased user demand.

If you want to have top-notch Ruby on Rails development services connect with Techvoot Solutions today. We have highly talented and expert ROR developers who have in-depth knowledge of building a functional and scalable website and application that will help you to expand your business. So, what are you waiting for? Hire our Ruby on Rails developers now.


Dhaval Baldha
Dhaval Baldha

Co-founder

Dhaval is a visionary leader driving technological innovation and excellence. With a keen strategic mindset and deep industry expertise, he propels the company towards new heights. His leadership and passion for technology make him a cornerstone of Techvoot Solutions' success.

Linkedin
Hire Skilled Developer

*Please fill all the required fields

Get our Newsletter

Customized solutions for your projects

*Please fill all the required fields