2011-11-20 6 views
10

J'utilise state_machine avec ActiveRecord sur l'une de mes applications Rails 3.1. J'ai trouvé que la syntaxe pour accéder aux enregistrements avec des états différents était lourde. Est-il possible de définir chaque état comme étant la portée en même temps sans écrire les définitions de portée à la main?Étendues nommées pour les états dans state_machine

Tenir compte exemple suivant:

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 

Répondre

2

J'ai aussi besoin de cette fonctionnalité, mais state_machine n'a rien de semblable. Bien que j'ai trouvé ce gist, mais aasm semble être une meilleure alternative de machine d'état dans ce cas.

+0

Merci, c'est vraiment utile. J'ai trouvé que la gemme 'state_machine' est meilleure dans mon cas, sauf ce problème avec les étendues. – Andrew

16

J'ajoute ce qui suit à mes modèles:

state_machine.states.map do |state| 
    scope state.name, :conditions => { :state => state.name.to_s } 
end 

Je ne sais pas si vous comptez cela comme « l'écriture définitions de la portée à la main? »

+0

Veuillez noter que ce code Lars doit être ajouté après le bloc state_machine. – tomaszbak

8

Juste au cas où, si quelqu'un cherche toujours cela, il existe des méthodes suivantes ayant été ajoutées lors de la définition 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) 

J'aime utiliser car il n'y aura jamais de conflit avec le nom de l'État. Vous pouvez trouver plus d'informations sur state_machine's ActiveRecord integration page.

Bonus est qu'il permet de passer ensemble, donc je fais souvent quelque chose comme:

scope :cancelled, lambda { with_state([:cancelled_by_user, :cancelled_by_staff]) } 
+0

L'OP le sait déjà. Il demande s'il peut créer différentes étendues nommées: 'Vehicle.parked' au lieu de' Vehicle.with_state (: garé) '. –

+0

thnx pour bonus))) c'est tout! – cubbiu

+0

Notez que dans Rails 3, named_scope a été renommé en portée. – cubbiu

0

Je vais vous montrer d'une manière qui peut être utilisé si le modèle a plusieurs state_machines aussi.

Cela fonctionne même dans le cas où vos états sont des entiers.

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 
Questions connexes