Gem Version Build Status Maintainability Test Coverage


Add this line to your application's Gemfile:

gem "flow"

Then, in your project directory:

$ bundle install
$ rails generate flow:install

What is Flow?

Flow is a SOLID implementation of the Command Pattern for Ruby on Rails.

Flows allow you to encapsulate your application's business logic into a set of extensible and reusable objects.

Quickstart Example

Install Flow to your Rails project:

$ rails generate flow:install

Then define State, Operation(s), and Flow objects.


A State object defines data that is to be read or written in Operation objects throughout the Flow. There are several types of data that can be defined, such as argument, option, and output.

$ rails generate flow:state Charge
# app/states/charge_state.rb

class ChargeState < ApplicationState
  # @!attribute [r]
  # Order hash, readonly, required
  argument :order
  # @!attribute [r]
  # User model instance readonly, required
  argument :user

  # @!attribute [r]
  # PaymentMethod model instance readonly, optional
  option :payment_method

  # @!attribute [rw]
  # Charge model instance readwrite, required
  output :charge


Operation objects execute some procedure defined in a #behavior method and can read and write to State data via defined accessor methods.

$ rails generate flow:operation CreateCharge
# app/operations/create_charge.rb

class CreateCharge < ApplicationOperation
  # @!attribute [r]
  # Order hash, readonly
  state_reader :order
  # @!attribute [r]
  # User model instance readonly
  state_reader :user
  # @!attribute [r]
  # PaymentMethod model instance readonly
  state_reader :payment_method

  # @!attribute [rw]
  # Charge model instance readwrite
  state_writer :charge

  def behavior
    state.charge = Charge.create(payment_method: payment_method, order: order, user: user)


  def payment_method
    payment_method.present? payment_method : user.default_payment_method

Use failure methods when an Operation and Flow should fail and no longer run:

$ rails generate flow:operation SubmitCharge
# app/operations/submit_charge.rb

class SubmitCharge < ApplicationOperation
  # @!method charge_unsuccessful_failure!(data = {})
  # Raises, stops the Operation and Flow, takes unstructured data hash
  failure :charge_unsuccessful

  # @!attribute [rw]
  # Charge model instance read only
  state_reader :charge

  def behavior
    charge_unsuccessful_failure!(response_body: response.body) unless success?

    charge.update(success: true)


  def success?
    response.body.success == "true"

  def response
  memoize :response


A Flow object is composed of one or more ordered Operations. Changes to the state will persist from one Operation to the next:

$ rails generate flow Charge
# app/flow/charge_flow.rb

class ChargeFlow < ApplicationFlow
  operations CreateCharge,


Trigger the Flow in your code with State inputs:

flow_input = {
  order: order,
  user: current_user,
  payment_method: visa_credit_card,

flow = ChargeFlow.trigger(flow_input)

Arguments defined on State are required when triggering a Flow, options are optional:

> ChargeFlow.trigger({})
ArgumentError: Missing arguments: order, user

State output can be accessed from the flow instance:

> flow = ChargeFlow.trigger(flow_input)

> flow.state.charge
=> #<Charge:0x00007fd5c5cda080 ... >

Success of the triggered Flow can be determined with these methods:

> flow.success?
=> true

> flow.failed?
=> false

If the Flow fails you can see the failures on the instance:

# some flow that results in a failure...
> flow = ChargeFlow.trigger(flow_input)

> flow.success?
=> false

# get the failure
> flow.operation_failure.problem
=> :charge_unsuccessful

# access unstructured hash passed into failure method
> flow.operation_failure.details.response_body
=> { some_response_body_here: ... }


Learn more with our wiki Getting Started page.

You also can download wiki to have offline access. Just simply do:

git clone [email protected]:RubyAfterAll/flow.wiki.git


The gem is available as open source under the terms of the MIT License.