Ever needed a progress bar for some long-running task in your Rails application? You searched Google and couldn't find anything that easily integrates with Rails? Well, we created a progress_job gem that helps with that problem.

Progress_job is a gem that builds upon delayed_job to give you a simple progress bar you can use in your views. Create a class with your long-running task inside, update the job in each iteration and have ajax calls that will update the progress bar.

ProgressJob

Progress_job depends on delayed_job, so I will write this tutorial using the delayed_job_active_record gem.

After adding the gem in your Gemfile

gem 'delayed_job_active_record' gem 'progress_job'

and running bundle install,

$ bundle install

run the progress_job generator to add migrations necessary for progress_job to work.

$ rails generate delayed_job:active_record $ rails generate progress_job:install $ rake db:migrate

This will add three columns to the delayed_jobs table:

progress_stage : string => customizable description for the current progress stage of the task

progress_current : integer => number representing the current progress value of the task

progress_max : integer => number representing the maximum progress value of the task

Then you can create a custom class extending ProgressJob::Base which will give you access to some handy methods for manipulating the job.

update_progress ( step: 10 ) # increase the progress_current for step update_stage ( 'name of stage' ) # change the progress_stage update_stage_progress ( 'name of stage' , step: 11 ) # change progress_stage and increase progress_current for step update_progress_max ( progress_max ) # change progress_max

Progress_job also gives you a route from which you can get all the info on a progress_job, and it is located at:

GET /progress-jobs/:job_id

Now all you need is an ajax call which will check the route every few seconds and update the progress bar visible on the screen.

Demo app

I've created a demo app. You can take a look at the demo or view its source.

# app/jobs/export.rb class ExportJob < ProgressJob :: Base def initialize ( users , progress_max ) super progress_max: progress_max @users = users end def perform update_stage ( 'Exporting users' ) csv_string = CSV . generate do | csv | @users . each do | user | csv << user . to_csv update_progress end end File . open ( 'path/to/export.csv' , 'w' ) { | f | f . write ( csv_string ) } end end # app/controllers/exports_controller.rb class ExportsController < ApplicationController def index end def export_users users = User . first ( 100 ) @job = Delayed :: Job . enqueue ExportJob . new ( users , users . count ) end end # app/views/exports/index.html.haml . export = link_to 'Export Users' , export_users_path , remote: true , class: 'btn btn-primary btn-lg' . well { style: 'display:none' } . row . col - xs - 12 . progress - status . text - primary . row . col - xs - 12 . progress . progress - striped . active . progress - bar . text - primary 0 % = link_to 'View csv' , '/system/export.csv' , class: 'btn btn-success export-link' , style: 'display:none' # config/routes.rb Rails . application . routes . draw do root to: 'exports#index' get 'export_users' => 'exports#export_users' , as: :export_users end