Gastón Ramos

Blog personal

← Volver al blog

Acts as state machine y metaprogramming

Recuperado del archivo original de WordPress.

Fe de erratas: En el artículo de abajo dónde expliqué cómo generar un named_scope por cada estado declarado con acts_as_state_machine hay un BUG el tema es así, los named_scope se definían en un método (self.define_named_scopes) que era llamado desde el constructor de la clase User, por consiguiente si queremos usar uno de estos named_scopes antes de que se instancie algún objeto de esta clase, el scope no existe, cómo era de esperar.

Entonces la solución rápida sería hacer directamente así:

class User   < ActiveRecord::Base
   acts_as_state_machine :initial => :inactive
   state :inactive
   state :active

event :active do transitions :from => :inactive, :to => :active end

######################################################## # define all state as named_scopes # self.states.each{|st| self.named_scope st, :conditions => { :state => st.to_s }, : order => 'created_at DESC' } end


Hace bastante que vengo usando la genial biblioteca "Acts as state machine" que nos permite tener un máquina de estados finita (o autómata finito) en un modelo Active Record y a partir de las últimas versiones en cualquier objeto Ruby, y desde hace un tiempito que vengo pensando "Qué bueno sería que ASSM te genere un named_scope por cada estado posible", entonces si por ejemplo tenemos 2 estados: active, inactive podríamos hacer algo así:

User.inactive # Esto retorna todos los usuarios con estado inactive
User.active # Esto retorna todos los usuarios con estado active

Bueno, acá está la solución que se me ocurrió:

class User   < ActiveRecord::Base
   acts_as_state_machine :initial => :inactive
   state :inactive
   state :active

event :active do transitions :from => :inactive, :to => :active end

def initialize(*args) self.class.define_named_scopes super *args end

def self.define_named_scopes self.states.each{|st| self.named_scope st, :conditions => { :state => st.to_s }, : order => 'created_at DESC' } end end

Nice eh! tenemos un método que escribe los named_scope por nosotros y seguro que se puede mejorar o quizás agregar una opción a AASM para que lo haga cuando lo deseemos, el tema es que cómo necesitamos la lista de los estados, debemos ejecutar esto después de especificar los mismos, aunque una solución más elegante sería modificar AASM y hacer que los named_scope se genere cada vez que especificamos un estado.

Hasta la próxima!

También puede interesarte

Comentarios del archivo (3)

Acts as state machine y metaprogramming · 20 de marzo de 2009

[...] (Via Gastón Ramos - Ruby, Rails&#8230;.) Original Link: Acts as state machine y metaprogramming [...]

gazer · 20 de marzo de 2009

Podés también hacer :
states.each do |st|
named_scope st, :conditions =&gt; { :state =&gt; st.to_s }, :order =&gt; 'created_at DESC'
end

Siempre y cuando lo pongas después de haber definido todos los states, quizás queda un poco más limpio.

Sin duda, si tenés más de un model que tenga estados, tal vez un patch para acts_as_state_machine que define el named_scope al definir el event sería más acorde :).

Gastón Ramos · 23 de marzo de 2009

Está casi igual que el mío sólo que sin el self? y yo lo "encerré" en un método para llamarlo en el constructor y de esa manera asegurarme que los named_scope se crean después de definir los estados. Pero de todos modos las posta sería poder hacer esto:

state :active, :named_scope =&gt; true

o

state :active, :named_scope =&gt; 'actives'

cómo diría una sabia mujer argentina: "Lo dejo a tu criterio ;)"

Los comentarios históricos se conservan como archivo. Para conversar hoy, podés escribirme.