Domanda

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!

È stato utile?

Soluzione

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

Altri suggerimenti

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?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top