Skip to content

Inputs - Defaults

Defaults answer: “If nobody passed this (or they passed nil), what should we use instead?” They run in the normal pipeline with coercion and validation, so a default isn’t a free pass — it still has to pass your rules.

Declarations

Defaults play nicely with coercion, validation, and nested inputs.

Static values

The boring (good!) kind: literals and empty collections.

class OptimizeDatabase < CMDx::Task
  input :strategy, default: :incremental
  input :level, default: "basic"
  input :notify_admin, default: true
  input :timeout_minutes, default: 30
  input :indexes, default: []
  input :options, default: {}

  def work
    strategy        #=> :incremental
    level           #=> "basic"
    notify_admin    #=> true
    timeout_minutes #=> 30
    indexes         #=> []
    options         #=> {}
  end
end

Symbol references

Delegate to an instance method when the fallback depends on context:

class ProcessAnalytics < CMDx::Task
  input :granularity, default: :default_granularity

  def work
    # ...
  end

  private

  def default_granularity
    Current.user.premium? ? "hourly" : "daily"
  end
end

Proc or Lambda

Tiny bits of logic without naming a method:

class CacheContent < CMDx::Task
  input :expire_hours, default: proc { Current.tenant.cache_duration || 24 }
  input :compression, default: -> { Current.tenant.premium? ? "gzip" : "none" }
end

Class or Module

Anything with #call(task) can compute the fallback:

class TenantDefaults
  def self.call(task)
    Current.tenant.cache_duration || 24
  end
end

class CacheContent < CMDx::Task
  input :expire_hours, default: TenantDefaults
end

Coercions and validations

After a default applies, the value walks the same path as user input: coerce → transform → validate.

class ScheduleBackup < CMDx::Task
  input :retention_days, default: "7", coerce: :integer
  input :frequency, default: "daily", inclusion: { in: %w[hourly daily weekly monthly] }
end

Note

Defaults trigger when the resolved value is nil. That includes “key missing” and “caller explicitly sent nil” — both count as “not really provided.”

Required + default = awkward

required: does not wait for defaults. If the key is missing, you get is required before defaults run. So required: true, default: ... fights itself: use optional ..., default: when you want a fallback, and required: when the caller must name the key.