Maintaining custom application tasks in Rails

Here are some hints on best practices to maintain your tasks in larger projects.

Rake Tasks vs. Scripts

  • The Rails default is using rake tasks for your application tasks. These live in lib/tasks/*.
  • In case you want to avoid rake for your tasks and just use plain ruby scripts, consider lib/scripts/* as folder.

Keeping tasks slim

For readability and testing it's easier to keep your tasks slim.

Example:

lib/gitlab/maintenance_tasks/user_export.rb:

module Gitlab
  module MaintenanceTasks
    class UserExport
      def export
        # Your code of exporting all users e.g. into a XSLX file
      end
    end
  end
end

As rake task: lib/tasks/gitlab.rb:

# bundle exec rake gitlab:user_export

namespace :gitlab do
  desc 'Export all users as XSLX'
  task user_export: :environment do
    Gitlab::MaintenanceTasks::UserExport.new.export
  end
end

As plain ruby script: lib/scripts/user_export.rb:

# bundle exec rails runner -e development lib/scripts/user_export.rb

Gitlab::MaintenanceTasks::UserExport.new.export

Testing should not be optional

Tasks should be tested the same way as other code, even if they are only run once.

Example:

spec/lib/gitlab/maintenance_tasks/user_export_spec.rb:

describe Gitlab::MaintenanceTasks::UserExport do
  it 'should export all users as XLSX file' do
    # Your code for testing all edge cases in the user export
  end
end

As rake task: spec/lib/tasks/gitlab_spec.rb:

describe 'lib/scripts/gitlab.rb' do   
  it 'calls the user export' do
    Rake::Task['gitlab:user_export'].invoke
      
    # Your code for testing e.g. that a file user_export.xlsx is written to disk (smoke test)
  end
end

As plain ruby script: lib/scripts/gitlab_spec.rb:

describe 'lib/scripts/gitlab.rb' do
  let(:script) { Rails.root.join(subject) }
    
  it 'calls the user export' do
    load(script)
    
    # Your code for testing e.g. that a file user_export.xlsx is written to disk (smoke test)
  end
end

Further reading

Emanuel 3 months ago