state machines vs enums
land sighted 🏝
Well we have come to the end dear readers, the Junior Engineer Academy is coming to an end for my cohort and I this Friday. We graduate and turn into less junior juniors, and throw our collective 🎓 into the air ( I’m assuming that there are 🎓 .. well there should be ). It has been quite a ride, ups and down and sideways at times, coming from my previous Sales roles software engineering is a far more cerebral pursuit where you migrate from feeling like a genius to the depths of despair in a relatively short period of time. I guess my advice to any junior / career changers out there, it might not all snap into place when you want it to, but it will happen over time, give it the time to come to you.
Find little niches that interests you, do the exercises, and read the books. If you’re anything like me you need to see that patterns a few times before they will start to take hold.
Also don’t forget that you are the sum of your previous non coding life / work experiences, these have value don’t hide or run away from them. Use them to your advantage they are your super power in software land, very few will have what you have.
the main course: the state machines vs. enums
the state 🤖
I’m going to pick on state machines first, and in particular the gem
state machines as it is the most popular on ruby toolbox, if you’re looking for rails support then head over and checkout out state machines active-record. Now I’m not saying that you should always just pick the first cab off the rank, but its expedient for this exercise al least. So what does it do exactly ?
State Machines adds support for creating state machines for attributes on any Ruby class.
So lets check our the readme from state machines active-record.
class Vehicle < ActiveRecord::Base
state_machine :initial => :parked do
before_transition :parked => any - :parked, :do => :put_on_seatbelt
after_transition any => :parked do |vehicle, transition|
vehicle.seatbelt = 'off'
end
around_transition :benchmark
event :ignite do
transition :parked => :idling
end
state :first_gear, :second_gear do
validates_presence_of :seatbelt_on
end
end
def put_on_seatbelt
...
end
def benchmark
...
yield
...
end
end
# scopes
Vehicle.with_state(:parked) # also plural #with_states
Vehicle.without_states(:first_gear, :second_gear) # also singular #without_state
# validations
state_machine do
state :first_gear, :second_gear do
validate :speed_is_legal
end
end
active record enums 🔢
A different tack to handling state is the use of enums, these get give you different states on a active record value, say a User
could be an “Admin”, “Student” or “Banned”, this was first introduced int to rails 4.1 .
How to get this up and running.
bin/rails g model phone number:string phone_number_type:integer
Which we can now give us :
# app/models/phone.rb
class Phone < ActiveRecord::Base
enum phone_number_type: [:home, :office, :mobile, :fax]
# or you can be explicit ( would recommend !!! )
enum phone_number_type: [:home 0, :office 1, :mobile 2, :fax 3]
end
Now we can get attributes in a new way.
# this
Phone.first.phone_number_type
3
# is now enum magic
Phone.first.phone_number_type
"fax"
We can also change them using the values Strings
or Integer
phone.phone_number_type = 1
phone.phone_number_type => "office"
phone.phone_number_type = "mobile"
phone.phone_number_type => "mobile"
you can now use a bang!
to define a enum
phone.office!
true
phone.phone_number_type
"office"
# and also
phone.office?
true
you can also get all of the types.
Phone.phone_number_types
{"home"=>0, "office"=>1, "mobile"=>2, "fax"=>3}
This makes life quite easy putting a select into a form like below.
<!--- app/views/phones/_form.html.erb --->
<div class="field">
<%= f.label :phone_number_type %><br>
<%= f.select :phone_number_type, Phone.phone_number_types.keys %>
</div>
That’s it for state machines vs enums, I look forward to seeing you on the other side of junior 👨🏻🎓
references: