Class: HasStateMachine::State

Inherits:
String
  • Object
show all
Extended by:
ActiveModel::Callbacks, ActiveModel::Model
Includes:
ActiveModel::Validations
Defined in:
lib/has_state_machine/state.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object, transient_values = {}) ⇒ State

Initializes the HasStateMachine::State instance.

Examples:

state = Workflow::Post::Draft.new(post) #=> "draft"


30
31
32
33
34
35
36
37
38
# File 'lib/has_state_machine/state.rb', line 30

def initialize(object, transient_values = {})
  @object = object

  transient_values.to_h.slice(*transients).each do |transient, value|
    instance_variable_set(:"@#{transient}", value)
  end

  super(state)
end

Instance Attribute Details

#objectObject (readonly)

Returns the value of attribute object.



11
12
13
# File 'lib/has_state_machine/state.rb', line 11

def object
  @object
end

#stateObject (readonly)

Returns the value of attribute state.



11
12
13
# File 'lib/has_state_machine/state.rb', line 11

def state
  @state
end

Class Method Details

.possible_transitionsObject



138
139
140
# File 'lib/has_state_machine/state.rb', line 138

def possible_transitions
  @possible_transitions || []
end

.stateObject



142
143
144
# File 'lib/has_state_machine/state.rb', line 142

def state
  to_s.demodulize.underscore
end

.state_options(transitions_to: [], transactional: false, transients: []) ⇒ Object

Set the options for the HasStateMachine::State classes to define the possible states the current state can transition to and whether or not transitioning to the state should be performed within a transaction.



158
159
160
161
162
163
164
165
166
167
168
# File 'lib/has_state_machine/state.rb', line 158

def state_options(transitions_to: [], transactional: false, transients: [])
  @possible_transitions = transitions_to.map(&:to_s)
  @transactional = transactional
  @transients = transients.map(&:to_sym)

  transients.each do |transient_name|
    define_method(transient_name) do
      instance_variable_get(:"@#{transient_name}")
    end
  end
end

.transactional?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/has_state_machine/state.rb', line 146

def transactional?
  @transactional || false
end

.transientsObject



150
151
152
# File 'lib/has_state_machine/state.rb', line 150

def transients
  @transients || []
end

Instance Method Details

#can_transition?(desired_state) ⇒ Boolean

Determines if the given desired state exists in the predetermined list of allowed transitions.

Parameters:

  • desired_state (String, Symbol)

    the state to check if the object can transition to

Returns:

  • (Boolean)

    whether or not the object can transition to the desired state



45
46
47
# File 'lib/has_state_machine/state.rb', line 45

def can_transition?(desired_state)
  possible_transitions.include? desired_state.to_s
end

#perform_transactional_transition!Object

Makes the actual transition from one state to the next and runs the before and after transition callbacks in a transaction to allow for roll backs.



94
95
96
97
98
99
100
101
102
# File 'lib/has_state_machine/state.rb', line 94

def perform_transactional_transition!
  ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
    run_callbacks :transition do
      rollback_transition unless object.update("#{object.state_attribute}": state)
    end
  end

  object.reload.public_send(object.state_attribute) == state
end

#perform_transition!Object

Makes the actual transition from one state to the next and runs the before and after transition callbacks.



84
85
86
87
88
# File 'lib/has_state_machine/state.rb', line 84

def perform_transition!
  run_callbacks :transition do
    object.update("#{object.state_attribute}": state)
  end
end

#possible_transitionsObject

possible_transitions - Retrieves the next available transitions for a given state. transactional? - Determines whether or not the transition should happen with a transactional block. state - The underscored name of the state transients - Specified list of optional transient attributes on this state



23
# File 'lib/has_state_machine/state.rb', line 23

delegate :possible_transitions, :transactional?, :state, :transients, to: "self.class"

#transitionObject

Defines the before_transition and after_transition callbacks for use on a HasStateMachine::State instance.



16
# File 'lib/has_state_machine/state.rb', line 16

define_model_callbacks :transition, only: i[before after]

#transition_to(desired_state, **options) ⇒ Boolean

Checks to see if the desired state is valid and then gives responsibility to the desired state’s instance to make the transition.

Parameters:

  • desired_state (String)

    the state to transition to

  • options (Hash)

    a hash of additional options for transitioning the object

Returns:

  • (Boolean)

    whether or not the transition took place



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/has_state_machine/state.rb', line 59

def transition_to(desired_state, **options)
  transitioned = false
  options = options.transform_keys(&:to_sym)
  desired_state_instance = state_instance(desired_state, options)

  with_transition_options(options) do
    return false unless valid_transition?(desired_state_instance)

    transitioned = if desired_state_instance.transactional?
      desired_state_instance.perform_transactional_transition!
    else
      desired_state_instance.perform_transition!
    end
  end

  transitioned
ensure
  (desired_state_instance&.errors || []).each do |error|
    object.errors.add(error.attribute, error.type)
  end
end