Rails: Workflow: Model implements State Machine

StateMachine is a gem that provides all the behavior necessary to implement workflow on your Model. Need an event that once it occurs on an instance on your Model will trigger an email? Or perhaps you need to access a REST service for verification once one of the instance’s fields is modified. Here is a sample suite where events and state transitions are set up for a Model to support workflow.


class MyModel < ActiveRecord::Base
  state_machine :status, :initial => :new do

    before_transition :on => :preapprove do |my_model|
      User.current ? user_id = User.current.id : user_id = 1
      @user = User.find_by(:id => user_id)
      log_entry = Approval.new(:approvable_type => 'MyModel',
                               :approvable_id => my_model.id,
                               :approved_by_user_id => user_id,
                               :approved_at => Time.now,
                               :event => 'preapprove',
                               :state => '')
      unless @user.blank? || @user.permanent_users.blank?
        log_entry.permanent_user_id = @user.permanent_users.first.id
      end
      log_entry.save!
    end

    before_transition :on => :approve do |my_model|
      User.current ? user_id = User.current.id : user_id = 1
      @user = User.find_by(:id => user_id)
      log_entry = Approval.new(:approvable_type => 'MyModel',
                               :approvable_id => my_model.id,
                               :approved_by_user_id => user_id,
                               :approved_at => Time.now,
                               :event => 'approve',
                               :state => '')
      unless @user.blank? || @user.permanent_users.blank?
        log_entry.permanent_user_id = @user.permanent_users.first.id
      end
      log_entry.save!
    end

    before_transition :on => :decline do |my_model|
      User.current ? user_id = User.current.id : user_id = 1
      @user = User.find_by(:id => user_id)
      log_entry = Approval.new(:approvable_type => 'MyModel',
                               :approvable_id => my_model.id,
                               :approved_by_user_id => user_id,
                               :approved_at => Time.now,
                               :event => 'decline',
                               :state => '')
      unless @user.blank? || @user.permanent_users.blank?
        log_entry.permanent_user_id = @user.permanent_users.first.id
      end
      log_entry.save!
    end

    after_transition :to => :preapproved do |my_model|
      my_model.approval_fields_required = true
    end

    after_transition :to => :contracted do |my_model|
      my_model.create_company_from_application
      my_model.create_user_from_application
      my_model.delay.notify_account_manager
      company = Company.tenant_companies.where(my_model: my_model.id).first
    end

    after_transition :to => :declined do |my_model|
      PartnerPathMailer.deliver("enrollment_vendor_declined", [my_model])
    end

    after_transition :to => :approved do |my_model|
      PartnerPathMailer.deliver("enrollment_vendor_approved", [my_model])
    end

    after_transition :to => :partner_declined do |my_model|
      PartnerPathMailer.deliver("enrollment_partner_declined", [my_model])
    end

    event :preapprove do
      transition :new => :preapproved
    end

    event :approve do
      transition :new => :approved
      transition :preapproved => :approved
      transition :change_requested => :approved
    end

    event :request_change do
      transition :approved => :change_requested
    end

    event :accept do
      transition :approved => :contracted
    end

    event :decline do
      transition :new => :declined
      transition :preapproved => :declined
      transition :change_requested => :declined
      transition :approved => :partner_declined
    end

  end
end