User status field, how to map to an enum - ruby-on-rails

I have a User model, and I want to have a user_status attribute.
I want this attribute to be stored as an integer in the database.
I was thinking of then creating a enum, and then mapping that enum to the integer value so I could do things like:
if user.status == MyEnum::RequiresApproval
..
..
Using active_record, at the model level, is there something I can do with the enum?
What is normally done in this kind of situation?

Enums are not very Rails like. State Machines are.
Check out the 'transitions' gem (link) (which was almost part of Rails Core)
And then you can do the following ...
#GemFile
gem "transitions", :require => ["transitions", "active_record/transitions"]
#And in your Model, do something like the following:
include ActiveRecord::Transitions
field :state, type: String
scope :active, where(state: 'active')
state_machine do
state :active
state :inactive
event :inactivate do
transitions :from => :active, :to => :inactive
end
event :activate do
transitions :from => :inactive, :to => :active
end
end
It was a transition for me too not to use enums and type tables -- but I haven't missed them

Related

using Acts as State Machine, how to set a specific time period for a given state?

given the below;
aasm do
state :available, :intitial => true
state :presented
state :invited
event :present do
transitions :from => :available, :to => :presented
end
event :invite do
transitions :from => :presented, :to => :invited
end
event :provide do
transitions :from => [:presented, :invited], :to => :available
end
end
what is an optimal pattern for setting the time period that an object 'lives under' a given state ?
ie, once the 'present' event occurs, I'd like the object to maintain the 'presented' state for exactly two hours, i'm feeling like I will have to mangle the way aasm works to achieve this, any thoughts ?
extra: this aasm code is being inserted into an active record class in a rails app, postgres is the db. Thx!

Set state values before initialization for state_machine

I'm using state_machine to manage approvals on an ActiveRecord::Base class.
I'm using custom state values so I can store states as integers. This works well, except that I am getting the following warning (from StateMachine::Machine) on Rails startup:
# Both MyClass and its :state machine have defined a different default
# for "state". Use only one or the other for defining defaults to avoid
# unexpected behaviors.
I'm not observing any unexpected behaviors, so this isn't a big deal. I know that I could remove the :default value from my table schema (e.g., :default => 0) to make this error go away, but I would prefer to do it on the state_machine side.
Here is the state_machine code (in my_class.rb):
# ...
States = {
:pending => 0,
:approved => 1,
:rejected => 2,
}
state_machine :state, :initial => :pending do
States.each do |name, value|
state name, :value => value
end
event :approve do
transition all => :approved
end
event :reject do
transition all => :rejected
end
end
The problem is that state_machine wants to set the initial/default value to "pending" before it realizes that the default value should actually be 0.
Is it possible to define my states pre-initialization? It would be nice if I could pass State objects or a StateCollection to the Machine initializer, but it doesn't look like that is possible (looking at the source at https://github.com/pluginaweek/state_machine/blob/master/lib/state_machine/machine.rb).

How to invoke Ruby gem AASM transition event given to and from states?

We have a Ruby on Rails application.
We're using Ruby's aasm gem to manage states of objects.
has_state
aasm do
state :created, :initial => true
state :submitted
state :rejected
state :approved
event :submit do
transitions :to => :submitted, :from => [:created]
end
event :mark_as_incomplete do
transitions :to => :created, :from => [:submitted]
end
event :approve do
transitions :to => :approved, :from => [:submitted]
end
event :reject do
transitions :to => :rejected, :from => [:submitted]
end
end
If we know an object's current state, which can be obtained using
object.aasm_current_state
and we also know the state to transition to, how can we invoke the event?
Please note, the from-state and to-state are variables, so we need to do the above
dynamically. Of course, with certain to-state and from-state combination, the transition isn't available, in that case we should detect an error.
We're also assuming between any two state combination (to-state and from-state), there's only 1 event, I think theoretically there can be more than 1.
I think this can be achieved by delving into the innards of aasm source code,
which, arguably, may not be a good practice. Any thoughts?
Just wonder if anyone has done this before.
Thanks!
There is no way provided by AASM to do this, but your own answer is getting already close enough to where you want to go. AASM is built around the assumption, that state machines allow multiple different transitions from one state to another.
If the event name is not relevant for you, you could reuse the to-state name as event name, like this:
aasm do
...
event :approved do
transitions :from => :submitted, :to => :approved
end
...
end
By this you can fire the event by just knowing the to-state name
approval_request.send(to_state)
By default, AASM raises an exception if this transition is not allowed. If you don't like the exception, set whiny_transitions to false, like this:
aasm :whiny_transitions => false do
...
end
This is the code I have. to_state and from_state are the states from and to.
ApprovalRequest.aasm_events.each do |event_key, event_obj|
if event_obj.transitions_from_state?(from_state) &&
event_obj.transitions_to_state?(to_state)
self.approval_request.send "#{event_key.to_s}!"
end
end
Any comments on this implementation?

Named scopes for states in state_machine

I use state_machine with ActiveRecord on one of my Rails 3.1 application. I found the syntax to access records with different states to be cumbersome. Is it possible to define each state to be the scope at the same time without writing scope definitions by hand?
Consider following example:
class User < ActiveRecord:Base
state_machine :status, :initial => :foo do
state :foo
state :bar
# ...
end
end
# state_machine syntax:
User.with_status :foo
User.with_status :bar
# desired syntax:
User.foo
User.bar
I'm adding the following to my models:
state_machine.states.map do |state|
scope state.name, :conditions => { :state => state.name.to_s }
end
Not sure if you count this as "writing scope definitions by hand?"
Just in case, if somebody is still looking for this, there are following methods added while defining state_machine:
class Vehicle < ActiveRecord::Base
named_scope :with_states, lambda {|*states| {:conditions => {:state => states}}}
# with_states also aliased to with_state
named_scope :without_states, lambda {|*states| {:conditions => ['state NOT IN (?)', states]}}
# without_states also aliased to without_state
end
# to use this:
Vehicle.with_state(:parked)
I like to use this because there will never be conflict with state name. You can find more information on state_machine's ActiveRecord integration page.
Bonus is that it allows to pass array so I often do something like:
scope :cancelled, lambda { with_state([:cancelled_by_user, :cancelled_by_staff]) }
I also needed this functionality, but state_machine has nothing similar. Although I've found this gist, but aasm seems like a better state machine alternative in this case.
I will show you a way which can be used if the model has multiple state_machines too.
It works even in the case when your states are integers.
def Yourmodel.generate_scopes_for_state_machines state_machines.each_pair do |machine_name, that_machine|
that_machine.states.map do |state|
# puts "will create these scopes: #{machine_name}_#{state.name} state: #{state.value} "
# puts "will create these scopes: #{machine_name}_#{state.name} state: #{state.name.to_s} "
# Price.scope "#{machine_name}_#{state.name}", :conditions => { machine_name => state.name.to_s }
Price.scope "#{machine_name}_#{state.name}", :conditions => { machine_name => state.value }
end end end
Yourmodel.generate_scopes_for_state_machines

Transitions class (state machine) get a list of possible transitions

I'm using a ActiveRecord::Transitions in Rails 3 and have my state machine defines as:
state_machine do
state :initial # first one is initial state
state :active
state :disabled
event :activate do
transitions :to => :active, :from => [:initial, :disabled]
end
event :disable do
transitions :to => :disabled, :from => [:initial, :active]
end
end
How do I see a list of available transitions for a current object and state?
For example if I have a #product in state "active" it should tell me
"disabled" is the only state available, or
"disable" is the only event available
I can't see any obvious way to enumerate possible-next-states, but you can query the available events like this:
YourClass.state_machines[:default].events_for(:active)
=> [:disable]
(If you have more than one state machine there will be additional members in the YourClass.state_machines Hash)
This answer is now more relevant
Basically - you have access to #product.state_evants, #product.state_transitions and #product.state_paths

Resources