[Tradução] Ruby on Rails Finite State Machine Plugin: acts_as_state_machine
janeiro 27th, 2008 | by Ramon Soares |Click aqui para ler a versão original em inglês
Uma Maquina de Estado Finito é um modelo de comportamento com um número finito de estados, interligados através de transições e eventos.
Neste guia, eu vou mostrar como o modelo de Maquina de Estado Finito pode ser recriado facilmente com um plugin do Ruby on Rails. O plugin que vamos usar é o acts_as_state_machine, que não é muito bem documentado. O Google retorna alguns resultados, mais não são muito bons, principalmente para iniciantes.
Porque você deve usar uma Maquina de Estado Finito?
Para iniciar, se seu modelo tem um numero finito de diferentes estados, e você procura uma maneira fácil de fazer chamadas entre as mudanças de estados, como uma notificação, validação, incremento ou qualquer outra coisa..
Instalando o acts_as_state_machine
Vá ate a pasta raiz de sua aplicação e execute:
$ ./script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk/
Usando o acts_as_state_machine
class Person < ActiveRecord::Base
acts_as_state_machine :initial => :sleeping
state :sleeping
state :showering
state :working
state :dating
event :shower do
transitions :from => :sleeping, :to => :showering
transitions :from => :working, :to => :showering
transitions :from => :dating, :to => :showering
end
event :work do
transitions :from => :showering, :to => :working
# Going to work before showering? Stinky.
transitions :from => :sleeping, :to => :working
end
event :date do
transitions :from => :showering, :to => :dating
end
event :sleep do
transitions :from => :showering, :to => :sleeping
transitions :from => :working, :to => :sleeping
transitions :from => :dating, :to => :sleeping
end
end
NOTA: O plugin assume que o estado de seu model fica no campo state. Isso pode ser substituido com a adição da opção :column => 'field'.
AVISO: Se você estiver usando um model que armazena endereços e existir o campo "state". Você passara horas se perguntando por que as coisas não funcionam.
Observe que na linha 2 é declarado explicitamente o estado inicial. Dá linha 4 à 7 são indicados os vários estados que o Person pode estar.
Existe um aspecto bem peculiar ao se criar objetos usando o metodo new, quando o estado do objeto não é informado. O estado só será especificado quando salvar o novo registro. Uma solução é especificar o valor padrão do estado dentro da migração. Outra solução é usar o método create
Exemplo:
person = Person.new person.state # nil person.save # true person.state # "sleeping" person = Person.create person.state # "sleeping" person.sleeping? # true person.rotting? # false person = Person.new person.state = "rotting" # "rotting" person.rotting? # true person.sleeping? # false
NOTA: Caso não tenha notado, o método para testar se o model“state?”
Os events que você especifica também criam métodos na instância, para transitar de um state para outro.
Segue exemplos dos métodos que foram criados:
person.shower! person.work! person.date! person.sleep!
NOTA: Os métodos criados seguem o padrão "event!"
Events
NOTA: Ao chamar um event, você também chama ActiveRecord::Base.save. Para quando ele falhar, apenas retorna false. Assegure-se de chamar valid? e save!.
Events ajuda a você a migrar de um state para outro. Supondo que seu person esteja dormindo (sleeping), e queremos que ele vá para o chuveiro (shower), é só chama shower!.
person.state # "sleeping" person.shower! person.state # "showering"
Events te ajuda a organizar o fluxo no seu model. Porem eles podem ficar mais “poderosos” com os callbacks.
Callbacks
O state possui alguns callbacks que podem ser usados.
state :sleeping,
:enter => :get_into_bed,
:after => Proc.new {|model| model.whack_alarm_clock },
:exit => :make_up_bed
Callbacks são chamados quando os models estão em transição para um state especifico.
NOTA:
Callbackspodem sersymbolouProc. Se usar umsymbol, um método da instancia domodelserá chamado.- Os
callbacksagem diferentes em ummodelsalvo de um novo e não salvo.
Levando em consideração as chamadas ActiveRecord, o callback de uma nova entrada seria:
- ActiveRecord::Base.before_save
- ActiveRecord::Base.save
- acts_as_state_machine :enter sleeping
- acts_as_state_machine :after sleeping
- ActiveRecord::Base.after_save
Se o model não é uma nova entrada, os callbacks executam o seguinte, se eu tiver chamado o método showe!.
- acts_as_state_machine :enter showering
- ActiveRecord::Base.before_save
- ActiveRecord::Base.save
- ActiveRecord::Base.after_save
- acts_as_state_machine :after showering
- acts_as_state_machine :exit sleeping
Protegendo os states
Mas como saber se você quer alguma espécie de validação para uma transição. Você sabe, só para garantir a integridade dos dados.
event :work do
transitions :from => :showering, :to => :working
# Going to work before showering? Stinky.
transitions :from => :sleeping, :to => :working, :guard => Proc.new {|o| o.clean? }
end
A transição pode ser protegida especificando a opção :guard com um symbol ou um Proc (semelhante aos callbacks). O método ou Proc deve retornar true para prosseguir com a transição, ou ira falhar silenciosamente.
UPDATE: 26-05-2008
LINKS
- http://diogenesf.wordpress.com/2007/12/11/acts_as_state_machine-gerenciando-estados-de-um-model-rails/
One Response to “[Tradução] Ruby on Rails Finite State Machine Plugin: acts_as_state_machine”
By Djalma on jan 28, 2008 | Reply
Fale mestre!