Question

How to Pass Command Line Arguments to a Rake Task in Ruby

rubycommand-linerakecommand-line-arguments

Question

I have a Rake task that needs to insert a value into multiple databases.

I want to pass that value into the Rake task either from the command line or from another Rake task.

How can I do this in Ruby?

Example context:

# I want something conceptually like this:
rake my_task[some_value]

Or I may want one Rake task to call another and provide that value programmatically.

Short Answer

By the end of this page, you will understand how Rake task arguments work in Ruby, how to pass values from the command line, how to pass values from one task to another, and when to use task arguments versus environment variables.

Concept

Rake allows tasks to accept named arguments. This is useful when a task needs input at runtime, such as an ID, a filename, an environment name, or a value that should be inserted into one or more databases.

In Ruby, a Rake task can declare parameters like this:

task :import, [:value] do |t, args|
  puts args[:value]
end

The key idea is:

  • :import is the task name
  • [:value] declares the task arguments
  • args[:value] reads the passed value inside the task

This matters because hardcoding values inside tasks makes automation brittle. Real projects often run tasks in different environments or with different inputs. Task arguments make the task reusable.

There are two common ways to pass data into a Rake task:

  1. Task arguments

    • Example: rake import[123]
    • Best when the task has a small number of explicit inputs
  2. Environment variables

    • Example: VALUE=123 rake import
    • Best when shells, CI systems, or deployment scripts already use environment-based configuration

When calling one Rake task from another, you can use invoke and pass arguments directly.

Rake::Task[:import].invoke("123")

So the main concept is not just “how do I pass a value,” but how to design parameterized automation tasks cleanly and predictably.

Mental Model

Think of a Rake task like a small command-line function.

  • The task name is the function name
  • The task arguments are the function parameters
  • The code block is the function body

For example, this Ruby method:

def greet(name)
  puts "Hello, #{name}"
end

is conceptually similar to this Rake task:

task :greet, [:name] do |t, args|
  puts "Hello, #{args[:name]}"
end

If you imagine a Rake task as a function that can be run from the terminal, the argument syntax becomes much easier to understand.

Take Quiz

Syntax and Examples

Basic syntax

A task with one argument:

task :insert_value, [:value] do |t, args|
  puts "Value received: #{args[:value]}"
end

Run it from the command line:

rake insert_value[hello]

In some shells, especially zsh, you may need quotes:

rake 'insert_value[hello]'

Example with multiple arguments

task :copy_data, [:source_db, :target_db, :value] do |t, args|
  puts "Copying #{args[:value]} from #{args[:source_db]} to #{args[:target_db]}"
end

Run it like this:

rake 'copy_data[main,archive,42]'

Example using environment variables

task :insert_value do
  value = ENV["VALUE"]
  puts "Value received: #{value}"
end

Run it like this:

VALUE=hello rake insert_value

Calling a task from another task

task :insert_value, [:value] do |t, args|
  puts "Inserting: #{args[:value]}"
end

task :run_import do
  Rake::Task[:insert_value].invoke("hello")
end

This lets one task reuse another instead of duplicating code.

A more practical database-style example

task :seed_value, [:value] do |t, args|
  value = args[:value]

  if value.nil? || value.strip.empty?
    puts "Please provide a value"
    next
  end

  databases = ["users_db", "orders_db", "analytics_db"]

  databases.each do |db|
    puts "Inserting #{value} into #{db}"
    # Database insertion code would go here
  end
end

Run it:

rake 'seed_value[test123]'

This example shows a common real-world pattern:

  • accept input
  • validate it
  • loop through targets
  • perform the operation

Step by Step Execution

Consider this task:

task :insert_value, [:value] do |t, args|
  value = args[:value]

  if value.nil? || value.empty?
    puts "Missing value"
    next
  end

  puts "Inserting #{value}"
end

Command:

rake 'insert_value[abc]'

Here is what happens step by step:

  1. Rake looks for a task named insert_value.
  2. It sees that the task expects one argument: :value.
  3. The string abc is passed into that argument.
  4. Inside the block, args[:value] returns "abc".
  5. The variable value is assigned "abc".
  6. The if condition checks whether the value is missing or empty.
    • It is not missing.
    • It is not empty.
  7. The task prints:
Inserting abc

If you run this instead:

rake 'insert_value[]'

then:

  1. The task still runs.
  2. args[:value] is empty or nil depending on how it is passed.
  3. The validation catches the missing input.
  4. The task prints:
Missing value

This is why input validation is important even for small automation tasks.

Real World Use Cases

Rake task arguments are useful in many practical Ruby projects.

Data maintenance

rake 'backfill_user_status[active]'

Use case:

  • backfilling missing records
  • updating old data after a schema change
  • running one-off migration helpers

Multi-database operations

rake 'sync_value[promo_2025]'

Use case:

  • insert a shared configuration value into several databases
  • update tenant-specific records
  • distribute seed data across environments

File processing

rake 'import_csv[customers.csv]'

Use case:

  • importing reports
  • parsing exports from another system
  • running local admin scripts

Scheduled jobs and CI pipelines

VALUE=release_17 rake publish_config

Use case:

  • passing deployment metadata
  • running tasks in automated pipelines
  • environment-based configuration in scripts

Admin and support tools

rake 'disable_user[1024]'

Use case:

  • support staff triggering safe maintenance tasks
  • one-off account updates
  • internal operational tooling
Take Quiz

Real Codebase Usage

In real codebases, developers often wrap business logic in plain Ruby objects or service classes, and keep the Rake task thin.

Common pattern: thin task, real logic elsewhere

class MultiDbInserter
  def self.call(value)
    databases = ["users_db", "orders_db"]

    databases.each do |db|
      puts "Inserting #{value} into #{db}"
    end
  end
end

task :insert_value, [:value] do |t, args|
  value = args[:value]

  if value.nil? || value.strip.empty?
    raise ArgumentError, "value is required"
  end

  MultiDbInserter.call(value)
end

Why this is common:

  • the task stays easy to read
  • the business logic can be tested separately
  • the same logic can be reused from scripts, jobs, or controllers

Guard clauses

Developers often validate arguments early:

task :process, [:id] do |t, args|
  raise ArgumentError, "id is required" unless args[:id]

  puts "Processing #{args[:id]}"
end

This avoids deep nesting and makes failures obvious.

Using reenable when calling a task more than once

A Rake task only runs once per process by default.

Rake::Task[:insert_value].invoke("a")
Rake::Task[:insert_value].invoke("b") # will not run again

If you want to run it again, re-enable it first:

Rake::Task[:insert_value].invoke("a")
Rake::Task[:insert_value].reenable
Rake::Task[:insert_value].invoke("b")

This is a very common source of confusion in larger task chains.

Environment variables for deployment scripts

Teams often prefer ENV when values come from CI/CD or shell scripts:

task :deploy_config do
  version = ENV.fetch("VERSION")
  puts "Deploying version #{version}"
end

This works well when external systems already manage configuration.

Common Mistakes

1. Forgetting to declare task arguments

Broken code:

task :insert_value do |t, args|
  puts args[:value]
end

Why it fails:

  • The task does not declare [:value], so the argument is not defined as expected.

Correct version:

task :insert_value, [:value] do |t, args|
  puts args[:value]
end

2. Not quoting the command in shells that expand brackets

Problematic command:

rake insert_value[hello]

In some shells, this may be interpreted by the shell instead of being passed to Rake.

Safer version:

rake 'insert_value[hello]'

3. Assuming a task can be invoked repeatedly without re-enabling

Broken expectation:

Rake::Task[:insert_value].invoke("one")
Rake::Task[:insert_value].invoke("two")

Why it surprises beginners:

  • The second call does nothing because Rake considers the task already executed.

Correct version:

Rake::Task[:insert_value].invoke("one")
Rake::Task[:insert_value].reenable
Rake::Task[:insert_value].invoke("two")

4. Not validating missing values

Broken code:

task :insert_value, [:value] do |t, args|
  puts args[:value].upcase
end

Why it fails:

  • If no value is passed, args[:value] may be nil, causing an error.

Safer version:

task :insert_value, [:value] do |t, args|
  value = args[:value]
  raise ArgumentError, "value is required" if value.nil? || value.empty?

  puts value.upcase
end

5. Putting too much logic directly in the task

This is not always broken, but it becomes hard to maintain.

Less ideal:

task :insert_value, [:value] do |t, args|
  # many lines of database logic here
end

Better:

class Inserter
  def self.call(value)
    # database logic here
  end
end

task :insert_value, [:value] do |t, args|
  Inserter.call(args[:value])
end

This makes testing and reuse easier.

Comparisons

ApproachExampleBest forNotes
Rake task argumentsrake 'import[123]'Small explicit inputsClean and readable for direct task usage
Environment variablesVALUE=123 rake importCI, scripts, deploymentGood when tools already provide env vars
Hardcoded valuesvalue written inside taskQuick experiments onlyNot flexible and not reusable

Task arguments vs environment variables

Task arguments

  • good for required positional inputs
  • easy to see from the command itself
  • useful when manually running tasks

Environment variables

  • good for external configuration
  • useful in CI/CD pipelines
  • better when passing many settings or secrets

Calling a task directly vs extracting logic to a class

PatternExampleWhen to use
Task contains all logicEverything inside task do ... endVery small one-off scripts
Task calls a class/serviceMyService.call(args[:value])Real applications and reusable code

In most production code, the second approach is easier to test and maintain.

Take Quiz

Cheat Sheet

Declare a task with arguments

task :name, [:arg1, :arg2] do |t, args|
  puts args[:arg1]
end

Run from the command line

rake 'name[value1,value2]'

Access arguments

args[:arg1]
args[:arg2]

Validate required input

raise ArgumentError, "arg1 is required" unless args[:arg1]

Call one task from another

Rake::Task[:name].invoke("value1", "value2")

Run a task again in the same process

Rake::Task[:name].reenable
Rake::Task[:name].invoke("new_value")

Use environment variables instead

task :name do
  value = ENV["VALUE"]
end

Run:

VALUE=test rake name

Good practice

  • keep tasks small
  • validate inputs early
  • move business logic into Ruby classes
  • quote bracket syntax in shells when needed

FAQ

How do I pass an argument to a Rake task from the command line?

Declare the task with arguments and run it like this:

task :example, [:value] do |t, args|
  puts args[:value]
end
rake 'example[hello]'

Why do I need quotes around task[arg]?

Some shells interpret square brackets before passing the command to Rake. Quotes ensure the full string reaches Rake unchanged.

How do I pass arguments from one Rake task to another?

Use invoke:

Rake::Task[:example].invoke("hello")

Why does my task only run once when I call it multiple times?

Rake tasks are executed once per process by default. Use reenable before invoking again.

Should I use task arguments or environment variables?

Use task arguments for small explicit inputs. Use environment variables when values come from CI, deployment scripts, or external shell environments.

Can a Rake task have multiple arguments?

Yes.

task :copy, [:from, :to] do |t, args|
  puts "#{args[:from]} -> #{args[:to]}"
end

What happens if an argument is missing?

The task still runs unless you validate the input yourself. Add guard clauses or raise an error when required values are missing.

Take Quiz

Mini Project

Description

Build a small Rake task that accepts a value and inserts it into a list of simulated databases. This project demonstrates how to define task arguments, validate input, loop through targets, and reuse the task from another task.

Goal

Create a Rake task that accepts a value from the command line and applies it to multiple database targets, with a second task that calls it programmatically.

Requirements

  • Create a Rake task named insert_into_all that accepts one argument called value
  • Validate that value is present before continuing
  • Simulate inserting the value into at least three databases by printing messages
  • Create another task named demo_insert that calls insert_into_all with a sample value
  • Make sure the first task can be called again from the same process if needed
Take Quiz

Keep learning

Related questions

View more