Jobler
Jobler helps you generate large reports or very large and slow pages through background jobs.
Install
Add it to your Gemfile and bundle it:
gem "jobler"
Install the migrations and run them:
rake railties:install:migrations
rake db:migrate
Add it to your routes:
mount Jobler::Engine => "/jobler"
Autoload the "Joblers" you are going to write through application.rb:
config.autoload_paths << Rails.root.join("app", "joblers")
Add a ApplicationJobler to follow the ApplicationController and ApplicationRecord pattern:
class ApplicationJobler < Jobler::BaseJobler
end
Jobler is going to queue its jobs through the ActiveJob queue called :jobler
, so make sure a worker is listening to that queue. This is done like this in Sidekiq:
bundle exec sidekiq --queue default --queue jobler --queue mailers
Usage
Write a new Jobler located in "app/joblers":
class MyJobler < ApplicationJobler
# This method will be executed in the background
def execute!
my_temp_file = Tempfile.new
# Do some heavy lifting code wise...
create_result!(name: "my-file", temp_file: my_temp_file)
end
# This method will be called from the web when the execute is completed and successful
def result
Jobler::FileDownload.new(
file_name: "some-file.zip",
temp_file: temp_file_for_result(name: "my-file")
)
end
end
You can do something like this in your controller:
class MyController < Jobler::BaseController
def some_action
scheduler = Jobler::JobScheduler.create! jobler_type: "MyJobler", job_args: {
current_user_id: current_user.id,
query_parameters: request.query_parameters
}
redirect_to jobler.job_path(scheduler.job)
end
end
This will show a wait page and them a complete page with a download link, once the job is completed.
Rendering views
First add a special controller that your Jobler's can use:
class ApplicationJoblerController < ApplicationController
end
Then call render from within the execute method:
class TestRenderJobler < Jobler::BaseJobler
def execute!
create_result!(
name: "render",
content: render(:show)
)
end
def result
Jobler::RedirectTo.new(url: "/jobler_jobs/jobs/#{job.to_param}")
end
end
This will render the view located at "app/joblers/test_render_jobler/show.*"
You should then create a controller something like this:
class JoblerJobsController < ApplicationController
def show
@job = Jobler::Job.find_by!(slug: params[:id])
@result = @job.results.find_by!(name: "render")
end
end
And a view in "app/views/jobler_jobs/show.html.erb":
<%= @result.result.force_encoding("utf-8").html_safe %>
You should also add a route like this:
Rails.application.routes.draw do
resources :jobler_jobs, only: :show
end
Progress bar
In order to utilize the progress bar and return some feedback on the progress to the user, you can implement a couple of calls to do that:
class MyJobler < ApplicationJobler
def execute!
progress_total collection.size
collection.find_each do |model|
increment_progress!
end
end
end
You can also call it from a view, if you a doing a render like this:
<% jobler.increment_progress! %>
You can also specify a custom value if it isn't 1:
<% jobler.increment_progress!(value: 5.0) %>
License
This project rocks and uses MIT-LICENSE.