Module: Sequel::Plugins::StateMachine::InstanceMethods
- Defined in:
- lib/sequel/plugins/state_machine.rb
Instance Method Summary collapse
- #audit(message, reason: nil, machine: nil) ⇒ Object
-
#audit_logs_for(machine) ⇒ Object
Return audit logs for the given state machine name.
- #audit_one_off(event, messages, reason: nil, machine: nil) ⇒ Object
- #commit_audit_log(transition) ⇒ Object
- #current_audit_log(machine: nil) ⇒ Object
-
#must_process(event, *args) ⇒ Object
Same as process, but raises an error if the transition fails.
- #new_audit_log ⇒ Object
-
#process(event, *args) ⇒ Object
Send event with arguments inside of a transaction, save the changes to the receiver, and return the transition result.
-
#process_if(event, *args) ⇒ Object
Same as must_process, but takes a lock, and calls the given block, only doing actual processing if the block returns true.
- #sequel_state_machine_status(machine = nil) ⇒ Object
-
#valid_state_path_through?(event, machine: nil) ⇒ Boolean
Return true if the given event can be transitioned into by the current state.
- #validates_state_machine(machine: nil) ⇒ Object
Instance Method Details
#audit(message, reason: nil, machine: nil) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/sequel/plugins/state_machine.rb', line 120 def audit(, reason: nil, machine: nil) audlog = self.current_audit_log(machine: machine) if audlog.class. audlog. ||= [] audlog. << else audlog. ||= "" audlog. += (audlog..empty? ? : ( + "\n")) end audlog.reason = reason if reason return audlog end |
#audit_logs_for(machine) ⇒ Object
Return audit logs for the given state machine name. Only useful for multi-state-machine models.
152 153 154 155 |
# File 'lib/sequel/plugins/state_machine.rb', line 152 def audit_logs_for(machine) lines = self.send(self.class.instance_variable_get(:@sequel_state_machine_audit_logs_association)) return lines.select { |ln| ln.sequel_state_machine_get(:machine_name) == machine.to_s } end |
#audit_one_off(event, messages, reason: nil, machine: nil) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/sequel/plugins/state_machine.rb', line 133 def audit_one_off(event, , reason: nil, machine: nil) = [] unless .respond_to?(:to_ary) audlog = self.new_audit_log mapped_values = audlog.sequel_state_machine_map_columns( at: Time.now, event: event, from_state: self.sequel_state_machine_status(machine), to_state: self.sequel_state_machine_status(machine), messages: audlog.class. ? : .join("\n"), reason: reason || "", actor: StateMachines::Sequel.current_actor, machine_name: machine, ) audlog.set(mapped_values) return self.add_audit_log(audlog) end |
#commit_audit_log(transition) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/sequel/plugins/state_machine.rb', line 86 def commit_audit_log(transition) machine = self.class.state_machines.length > 1 ? transition.machine.name : nil StateMachines::Sequel.log( self, :debug, "committing_audit_log", {transition: transition, state_machine: machine}, ) current = self.current_audit_log(machine: machine) last_saved = self.audit_logs.find do |a| a.sequel_state_machine_get(:event) == transition.event.to_s && a.sequel_state_machine_get(:from_state) == transition.from && a.sequel_state_machine_get(:to_state) == transition.to end if last_saved StateMachines::Sequel.log(self, :debug, "updating_audit_log", {audit_log_id: last_saved.id}) last_saved.update(**last_saved.sequel_state_machine_map_columns( at: Time.now, actor: StateMachines::Sequel.current_actor, messages: current., reason: current.reason, )) else StateMachines::Sequel.log(self, :debug, "creating_audit_log", {}) current.set(**current.sequel_state_machine_map_columns( at: Time.now, actor: StateMachines::Sequel.current_actor, event: transition.event.to_s, from_state: transition.from, to_state: transition.to, )) self.add_audit_log(current) end @current_audit_logs[machine] = nil end |
#current_audit_log(machine: nil) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/sequel/plugins/state_machine.rb', line 66 def current_audit_log(machine: nil) @current_audit_logs ||= {} alog = @current_audit_logs[machine] if alog.nil? StateMachines::Sequel.log(self, :debug, "preparing_audit_log", {}) alog = self.new_audit_log if machine machine_name_col = alog.class.state_machine_column_mappings[:machine_name] unless alog.respond_to?(machine_name_col) msg = "Audit logs must have a :machine_name field for multi-machine models or if specifying :machine." raise InvalidConfiguration, msg end alog.sequel_state_machine_set(:machine_name, machine) end @current_audit_logs[machine] = alog alog.sequel_state_machine_set(:reason, "") end return alog end |
#must_process(event, *args) ⇒ Object
Same as process, but raises an error if the transition fails.
170 171 172 173 174 |
# File 'lib/sequel/plugins/state_machine.rb', line 170 def must_process(event, *args) success = self.process(event, *args) raise StateMachines::Sequel::FailedTransition.new(self, event) unless success return self end |
#new_audit_log ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/sequel/plugins/state_machine.rb', line 54 def new_audit_log assoc_name = self.class.instance_variable_get(:@sequel_state_machine_audit_logs_association) unless (audit_log_assoc = self.class.association_reflections[assoc_name]) msg = "Association for audit logs '#{assoc_name}' does not exist. " \ "Your model must have 'one_to_many :audit_logs' for its audit log lines, " \ "or pass the :audit_logs_association parameter to the plugin to define its association name." raise InvalidConfiguration, msg end audit_log_cls = audit_log_assoc[:class] || Kernel.const_get(audit_log_assoc[:class_name]) return audit_log_cls.new end |
#process(event, *args) ⇒ Object
Send event with arguments inside of a transaction, save the changes to the receiver, and return the transition result. Used to ensure the event processing happens in a transaction and the receiver is saved.
160 161 162 163 164 165 166 167 |
# File 'lib/sequel/plugins/state_machine.rb', line 160 def process(event, *args) self.db.transaction do self.lock! result = self.send(event, *args) self.save_changes return result end end |
#process_if(event, *args) ⇒ Object
Same as must_process, but takes a lock, and calls the given block, only doing actual processing if the block returns true. If the block returns false, it acts as a success. Used to avoid issues concurrently processing the same object through the same state.
180 181 182 183 184 185 186 |
# File 'lib/sequel/plugins/state_machine.rb', line 180 def process_if(event, *args) self.db.transaction do self.lock! return self unless yield(self) return self.must_process(event, *args) end end |
#sequel_state_machine_status(machine = nil) ⇒ Object
50 51 52 |
# File 'lib/sequel/plugins/state_machine.rb', line 50 def sequel_state_machine_status(machine=nil) return self.send(self.state_machine_status_column(machine)) end |
#valid_state_path_through?(event, machine: nil) ⇒ Boolean
Return true if the given event can be transitioned into by the current state.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/sequel/plugins/state_machine.rb', line 189 def valid_state_path_through?(event, machine: nil) current_state_str = self.sequel_state_machine_status(machine).to_s current_state_sym = current_state_str.to_sym sm = find_state_machine(machine) event_obj = sm.events[event] or raise ArgumentError, "Invalid event #{event} (available #{sm.name} events: #{sm.events.keys.join(', ')})" event_obj.branches.each do |branch| branch.state_requirements.each do |state_req| next unless (from = state_req[:from]) return true if from.matches?(current_state_str) || from.matches?(current_state_sym) end end return false end |
#validates_state_machine(machine: nil) ⇒ Object
204 205 206 207 208 209 210 211 |
# File 'lib/sequel/plugins/state_machine.rb', line 204 def validates_state_machine(machine: nil) state_machine = find_state_machine(machine) states = state_machine.states.map(&:value) state = self.sequel_state_machine_status(state_machine.attribute) return if states.include?(state) self.errors.add(self.state_machine_status_column(machine), "state '#{state}' must be one of (#{states.sort.join(', ')})",) end |