我正在rails 4上编写一个类似于kickstarter或indiegogo的电子商务平台。产品的状态在很大程度上取决于各种条件,例如订单是否足够。因此,例如,如果我使用gem state_machine
,我的代码可能看起来像这样。
class Product < ActiveRecord::Base
has_many :orders
state_machine :initial => :prelaunch do
event :launch do
transition :prelaunch => :pending, :if => lambda {|p| p.launch_at <= Time.now }
end
event :fund do
transition :pending => :funded, :if => :has_enough_orders?
end
end
def has_enough_orders?
if orders.count > 10
end
end
然后我可能会创建一个模型观察者,这样每次下订单时我都会检查product.has_enough_orders?
,如果返回true
,我会调用product.fund!
。因此,has_enough_orders?
被多次检查。这似乎不是很有效。
此外product.launch!
也存在类似问题。我可以考虑实现它的最佳方法是使用类似sidekiq
的内容,并且有一项工作可以检查是否有任何预启动的产品在launch_at
时间内通过。然而,这似乎同样很脏。
我只是在想它,或者你通常会如何使用状态机?
答案 0 :(得分:5)
我刚刚修改了状态机以更好地处理条件。
您可以使用after_transition
或before_transition
方法
class Product < ActiveRecord::Base
has_many :orders
state_machine :initial => :prelaunch do
after_transition :prelaunch, :do => :check_launch
after_transition :pending, :do => :has_enough_orders?
event :launch do
transition :prelaunch => :pending
end
event :fund do
transition :pending => :funded
end
end
def check_launch
if launch_at <= Time.now
self.launch # call event :launch
else
# whatever you want
end
end
def has_enough_orders?
if orders.count > 10
self.fund # call event :fund
else
# whatever you want
end
end
end