Module: ConcernsOnRails::Models::Stateable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/concerns_on_rails/models/stateable.rb
Overview
Lightweight, string-backed state machine — the common 80% of a state machine without an AASM-sized dependency.
class Article < ApplicationRecord
include ConcernsOnRails::Stateable
stateable_by :status,
states: %i[draft pending published archived],
default: :draft,
transitions: {
publish: { from: %i[draft pending], to: :published },
archive: { to: :archived } # :from omitted => any state
}
end
Generates, for each state (method names honor prefix:/suffix:):
* predicate — article.draft? => status == "draft"
* scope — Article.draft => where(status: "draft")
* setter — article.published! => update!(status: "published") (unguarded)
And for each declared transition:
* event! — article.publish! => guarded; raises InvalidTransition from a bad state
* guard? — article.may_publish? => whether the transition is allowed now
Plus a generic ‘transition_to!(state)`.
Options for stateable_by: default:, transitions:, prefix:, suffix: (prefix:/suffix: take ‘true` to use the field name, or a literal string/symbol).
Notes:
* String columns only (store the state name) — not integer-backed like Rails enum.
* A state named like an AR method (`new`, `valid`) or a concern scope
(`active`, `expired`) will clash — use prefix:/suffix: to disambiguate.
Defined Under Namespace
Modules: ClassMethods Classes: InvalidTransition
Constant Summary collapse
- LABEL =
"ConcernsOnRails::Models::Stateable".freeze
Instance Method Summary collapse
-
#transition_to!(state) ⇒ Object
Move to any declared state by name, bypassing transition guards.
Instance Method Details
#transition_to!(state) ⇒ Object
Move to any declared state by name, bypassing transition guards.
56 57 58 59 60 61 |
# File 'lib/concerns_on_rails/models/stateable.rb', line 56 def transition_to!(state) state = state.to_sym raise InvalidTransition, "#{LABEL}: '#{state}' is not a declared state" unless self.class.stateable_states.include?(state) update!(self.class.stateable_field => state.to_s) end |