Ruby on Rails recently added a built-in ActiveRecord::StateMachine implementation and even more recently tied it in to ActiveRecord. And, for being a built-in library, it’s pretty damned fully-featured. Really, if this one doesn’t do it for you, then you probably need to write it yourself, anyway.
And, if you’re thinking that you don’t know what a state machine is, or think that you’ve never used one, think again. If you’ve ever used the restful_authentication plugin, you’ve probably used a state machine. In that library, Users can be pending, active, inactive … It’s all the same object, just acting differently depending on its current situation. That, in a nutshell, is a state machine.
Let’s start with an example that most people might recognize:
class TrafficLight < ActiveRecord::Base
include ActiveRecord::StateMachine
state_machine do
state :red
state :green
state :yellow
event :change_color do
transitions :to => :red, :from => [:yellow], :on_transition => :catch_runners
transitions :to => :yellow, :from => [:green]
transitions :to => :green, :from => [:red]
end
end
def catch_runners
puts "That'll be $250."
end
end
light = TrafficLight.new
light.current_state #=> :red
light.change_color! #=> true
light.current_state #=> :green
light.change_color! #=> true
light.current_state #=> :yellow
light.change_color! #=> true
"That'll be $250."
So, that’s a basic state machine. The light changes from red to green to yellow to red. That’s it. It’s a boring life for a stop light. Certainly, this isn’t a glamorous example, but there are some interesting points here:
- The initial state for the TrafficLight is red, which is the first state defined.
- On a successful transition to red (from yellow), the local
catch_runnersmethod is executed. - The model acts differently depending on its current state, for instance, the
change_color!method has a different action depending on the current color of the light.
And that’s not all. The built-in StateMachine also supports success callbacks per event, enter and exit callbacks per state, guards on transitions, and a lot more:
event :sample, :success => :we_win do; ...; end
state :open, :enter => [:alert_twitter, :send_emails], :exit => :alert_twitter
event :close do # You may only close the store if the safe is locked!! transitions :to => :closed, :from => :open, :guard => :safe_locked? end
So, if you’ve ever used the AASM plugin, you’ll probably feel right at home here with the ActiveRecord::StateMachine. I’m finding myself quite comfortable. In fact, I just might relocate.
Photo credit: Go and Stop
Related posts:







There is a state machine built into Rails Since when! http://bit.ly/M8DaW
This comment was originally posted on Twitter
Learn more about the new Rails state machine on the Envy Labs blog at http://bit.ly/M8DaW
This comment was originally posted on Twitter
Excellent… will it be backported for 2.3.x? or is it a 3.0-only feature?
– nachokb
It’s interesting that they have rolled this into core, where in the past they have extracted such items such as “acts_as_tree” into plugins.
I’m pleased to see the influence of AlterEgo (http://alter-ego.rubyforge.org/), in the form of state-based polymorphism and my much-abused traffic light example, making it into ActiveRecord :-)
Wuhoo! State machine now merged to ActiveRecord http://bit.ly/EUcDp
This comment was originally posted on Twitter
Love it!
Available…. when ?
@nachokb and @elad: Exactly when it will be released into a formal release, I can’t say for sure. It is already in the mainline release branch, so I would assume that it would hit the next 2.3.x release unless 3.0 were to be released before that time. It shouldn’t be necessary to back-port.
@avdi: Thanks for stopping in and looking this over. I must admit that I’m a state machine junkie. I think alter-ego is probably the closest to the true Gang of Four implementation that I’ve seen of a SM in Ruby. Great job on it. I certainly apologize for the traffic light example, it was inspired by the test cases in Rails for the new StateMachine module. Which, probably, was inspired by your Alter Ego post. :)
Ruby on Rails recently added a built-in ActiveModel::StateMachine implementation. This is really cool! via @envylabs http://bit.ly/58EzT
This comment was originally posted on Twitter
The Rails State Machine « Envy Labs http://bit.ly/10zZWy
This comment was originally posted on Twitter
state machines built into new activerecord http://bit.ly/M8DaW
This comment was originally posted on Twitter
Finally some updates, thanks Nathaniel, you are doing a very good work :)
This comment was originally posted on Riding Rails
I’m really pleased that the core has a state machine, however I think there is a better impl which is http://github.com/sbfaulkner/has_states/tree/master, you can have multiple state columns and it overcomes the following limitations with aasm (and possibly AR:SM), “Validations and guards were redundant, transitions were not observable and direct manipulation of state attributes did not result in transitions.” The latter especially useful in RESTful manipulation of states. Maybe these limitations have been overcome in the core version, but at a glace it looked like a port of aasm. Cheers.
[...] The Rails State Machine « Envy Labs A interesting writeup on the new ActiveModel::StateMachine implementation [...]
Am I the only one that has a problem with this? I thought we were supposed to be taking bloat out of core rather than putting more into it. A state machine implementation really doesn’t seem like core functionality to me. Additionally, I might prefer one state machine implementation over the other.
I don’t get it.
Кириллица is great! :)
This comment was originally posted on Riding Rails
Thanks Andrea. I’m aiming to get an Edge Rails post out around once every week for the foreseeable future.
This comment was originally posted on Riding Rails
Dan: You’re not the only one. I don’t get it too.
why would you add a state_machine to core? http://bit.ly/EUcDp – I thought we were going for less bloat, not more
This comment was originally posted on Twitter
@dan I think it’s important to note that a simple state machine implementation would likely be quite useful internally to core. Often, SMs can clean up logic and make intent more easily conveyed. But, as far as I’ve seen, it hasn’t yet been used anywhere in the core.
@simmsy I can certainly agree with some of your feelings towards AASM, although I’m not sure I’d be on board with “manipulation of state attributes” resulting in transitions. That seems a little awkward to me. I would rather my state attribute be closed to the world and entirely private to the instance. I prefer always transitioning my SMs via a transition method, which allows for callbacks and more complex logic than just change A to B. It seems like bad form to potentially allow an external party to randomly define your state value.
Clean, concise and to the point.Nice Post Nathaniel!
This comment was originally posted on Riding Rails
why would you add a state_machine to core? http://bit.ly/EUcDp – I thought we were going for less bloat, not more (via @dpickett) ++++
This comment was originally posted on Twitter
Envy Labs blog is bringing the goods thus far: http://bit.ly/M8DaW
This comment was originally posted on Twitter
@nathaniel: No apology needed, since I think I lifted the traffic light example from the Gang of Four :-)
A feature best demonstrated with a silly example or a fib(n) example is perhaps a feature pushed into a plugin :)
This comment was originally posted on Riding Rails
I also don’t like it as a core feature, hope it would be extracted into a plugin.
@DanPickett: A state machine is such a frequently used pattern that having one in the core seems like a bonus. If you’re a savvy developer with a preferred implementation you’re still welcome to use whatever you like.
I think we have to look at this addition in context of the other changes in Rails 3. Specifically, Rails 3 is becoming more modular so you’ll be able to take what you need and leave what you don’t. If you look at the example, he had to mix in the functionality – it wasn’t bloating AR::Base by default. With that in mind, it’s pretty much a win all around. State machines are so common (multi-step processes like signups and checkouts are the norm), it’s great to have the functionality in the framework. Rails will always let you choose something else but having an officially supported state machine implementation out of the box is a nice bonus.
Just for clarification: is ‘edge’ the next 2.3.x release, or have all these features/changes only made it into the 3.x branch?
This comment was originally posted on Riding Rails
@Dr NicGood point. Could be a rule of thumb.@NathanielGreat job, we really do need more of these posts.Thanks
This comment was originally posted on Riding Rails
Rails 3.0 will have state machine built into AR. file under unexpected and pleasant surprise. http://tr.im/vL9P
This comment was originally posted on Twitter
More info on Rails built in State Machine http://bit.ly/EUcDp
This comment was originally posted on Twitter
Glad to see TWIER starting up again. Have fun!
This comment was originally posted on Riding Rails
austinfromboston and Christian Romney++ Glad I refreshed the article I’d had open for awhile before replying :-)
As long as it’s a mixin, it’s a welcome addition to me. One less plugin needed for pretty much every app I have with user signups, and it’s a well-defined, archetypal pattern where a stable API in core can stand as a reference implementation.
Rails 3.0 will have state machine built into AR. file under unexpected and pleasant surprise. http://tr.im/vL9P (via @assaf)
This comment was originally posted on Twitter
[...] The Rails State Machine Rails edge recently added built-in state machine functionality. Here’s a few examples of how you might take advantage of this feature. [...]
Rails edge got a state machine component built in http://bit.ly/M8DaW
Good or bad?
This comment was originally posted on Twitter
I’m glad to see this getting added to the core. A preferred state machine is a win.
I’m happy too! …never have to worry about it not working with future versions..
State Machine module added into default #Rails. No more need for AASM, by the looks of it http://bit.ly/4jlvtM
This comment was originally posted on Twitter
Add me to the list of guys who don’t get why this is in core
Rails state machines in ActiveRecord #rails – http://bit.ly/M8DaW
This comment was originally posted on Twitter
ActiveModel::StateMachine: http://bit.ly/7zxSb I’ve written hacked state machines in my code but with this, no more. Too bad it’s tied to AM
This comment was originally posted on Twitter
What I don’t get is why this is in core *but authentication isn’t*.
Encoding issues still annoys the hell out of me. I hope I don’t have to do things like http://bit.ly/zr1Pg in 3.0.With that said, 3.0 will solve so many problems. You should jump straight to 7.0 or something, to reflect the awesomeness.
This comment was originally posted on Riding Rails
It would be nicer as a plugin, but I’m not fussed. These defaults are what makes Rails so great! People are more likely to use something built into Rails and compatibility maintained between versions. Makes things easier for new developers joining a project. I read somewhere that 3.0 will include a background task system too, which will be great!
[...] ActiveRecord::StateMachine (announced) [...]
ActiveModel::StateMachine as part of core in Rails 3? (http://bit.ly/2hktsT) … neat, but wonder about the rationale.
This comment was originally posted on Twitter
Ohh – State Machine in Edge Rails. Nice. http://tr.im/vOnQ
This comment was originally posted on Twitter
Rails3 將內建 state_machine http://bit.ly/M8DaW
This comment was originally posted on Twitter
I think core should have released this as a gem.
Between app templates, geminstaller and config.gems any pain associated with installing gems is reduced to almost nothing. It would add seconds to an app developers time, but it will add to the burden of developers who want to contribute to rails since it’s one more thing that could break.
And if we’re talking about adding to the framework, how about pulling in will_paginate. Every rails app I’ve ever seen uses will_paginate, and there are no other viable alternatives to my knowledge, nor are there any serious arguments about it’s implementation. But will_paginate is not in core.
From a support standpoint, I think rails core just added more work for themselves unecessarily. If it were a gem, they could open up the core contributor list to people like authors of other state_machine gems, managed it in a separate lighthouse project and if it fails, let it die gracefully, like acts_as_nested_set. If this makes it into a release, it’s just one more piece of noise that will take up core members time and divert attention from making less controversial parts of the framework better.
It’s quite interesting, thanks Nathaniel. But as Jeff Dean, I don’t see the point to include this in the core framework. This is making it more fat. Plugin or gem are better place as it’s fit for specific situations.
When Rails 2 was released, all parts that were not needed and could be released as a plugin/gem like acts_as_list, acts_as_nested_set were externalized.Now, there are implementing states machines in ActiveRecord, but many plugins already exist for that (AASM, PluginaWeek state_machine)…I don’t understand the current philosophy of Rails Core.
This comment was originally posted on Riding Rails
Totally agree with Jeff and Renoke. Even this can be very useful, it is probably better to be released as a gem. What about ActiveStateMachine ? :)
ActiveRecord::StateMachine is kinda cool… http://bit.ly/7zxSb
This comment was originally posted on Twitter
[...] The Rails State Machine « Envy Labs [...]
The Rails State Machine « Envy Labs http://bit.ly/9gzWu rubyonrails patterns software webdev statemachine ruby
This comment was originally posted on Twitter
Most of us are coding state machine support code into models anyway. after_saves and the like running conditionally in our models are doing what this DSL can express more elegantly. I’m hanging out for the controller equivalent for stateful navigation to clean up before_filter support logic.
Would core benefit from inclusion? Six of one, half a dozen of the other. Simply ’six’ is more direct IMHO.
[links] The Rails State Machine http://bit.ly/1XmVQx
This comment was originally posted on Twitter
Nova semana, novas novidades…. algumas controvérsias sobre a inclusao de uma StateMachine no core…. http://tinyurl.com/n9dcjy
This comment was originally posted on Twitter
Ruby on Rails agora tem StateMachines embutido por padrão! http://bit.ly/M8DaW
This comment was originally posted on Twitter
[...] The Rails State Machine « Envy Labs [...]
I really like the idea of a built in statemachine for Rails http://bit.ly/M8DaW
This comment was originally posted on Twitter
#rubyonrails #rails implements state machine http://bit.ly/13JQq3
This comment was originally posted on Twitter
I like it in the core, i use it quite often and a i think simple state machine fit well in activerecord.
Thanks for the post.
Goodbye AASM – Hello http://bit.ly/M8DaW
This comment was originally posted on Twitter
State machine logic being rolled into Rails Core: http://bit.ly/M8DaW
#rails
This comment was originally posted on Twitter
Interesting. Please consider taking my 5 minute survey on models that includes questions on state machines use.
http://spreadsheets.google.com/viewform?hl=en&cfg=true&formkey=cFZqeVg0cGZzZkZpSFl1SVNjaFI2UEE6MA..
http://spreadsheets.google.com/viewform?hl=en&cfg=true&formkey=cFZqeVg0cGZzZkZpSFl1SVNjaFI2UEE6MA..
any information on how the state machine is implemented inside ruby?
your example doesn’t work anymore.
You need to change:
include ActiveRecord::StateMachine
to:
include ActiveModel::StateMachine
@silas Thanks. The post has been updated to reflect the move to ActiveModel from ActiveRecord.
Actually I was incorrect. ActiveModel isn’t persistent while ActiveRecord is.
It appears that as of Rails 2.3.4 this functionality is not included. Is this slated for 2.3.x or 3.0 ?
I also agree that this little utility should be in the core. Come on, you always end up needing a state machine, one way or another.
Here you have a state pattern based alternative that integrates with ActiveRecord: http://github.com/dcadenas/active_record_state_pattern
The library intentionally follows the classic state pattern implementation (no state mixins, classical delegation to simple state classes, etc.) believing that by doing so we increase flexibility (internal DSL constraints vs plain object oriented Ruby power), simplicity and clarity.
Any update about when this is slated for release – 3.0? Where is the official ‘timeline’ for release feature sets – lighthouse?
I don’t get why people are complaining about why its in core… Its not a big deal! It’s a mixin! Its not in by default, it doesn’t bloat anything, its just an extra piece of love that you can use if you want. Every project I’ve ever done needed a state machine, one way or another – so I welcome this functionality with open arms.
This looks great but I too am wondering if I should wait for a 2.3.x minor release or if this is a 3.0 feature. I spent a little while trying to find that information with no luck.
As per the rails 3.0 beta release notes ActiveRecord::StateMachine has been removed from the rails 3.0 release. Does anyone know whether this module will be released as a separate gem?
[...] The Rails State Machine Ruby on Rails recently added a built-in ActiveModel::StateMachine implementation and even more recently tied it in to ActiveRecord. And, for being a built-in library, it’s pretty damned fully-featured. [...]
@tonymi — apparently Jeremy took it out, saying something to the effect “a StateMachine implementation is not needed — you can just use Ruby”. Not exactly sure what he means by this though…