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



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.



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.



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