Kikyo

使用AASM管理对象状态

某库存系统项目,有公司库存两种模型,一个公司有多个产品的库存信息。

class Company
  has_many :stocks
end
class Stock
  belongs_to :company
end

公司有新建(pending)激活(active)两种状态,库存有新建(pending)已支付(paid)激活(active)3种状态,公司的状态会影响库存状态。

库存信息支付后状态变为已支付,然后激活公司,库存信息状态变为激活。 若公司从激活变为未激活,已支付的库存信息状态从激活变为已支付。

在最早期的实现里,状态的控制都是手动完成,整个流程都很混乱,要引入新的状态非常困难。

后来经过重构,使用aasm来管理这些状态。

https://github.com/aasm/aasm

使用AASM管理状态

公司(Company)

class Company
  has_many :stocks
  aasm :column => :state, :whiny_transitions => false do
    state :pending, :initial => true
    state :active

    event :up do
      transitions :from => :pending, :to => :active,
        if: :company_actived?, success: ->{ stocks.each(&:up!) }
    end

    event :down do
      transitions :from => :active, :to => :pending,
        unless: :company_actived?, success: ->{ stocks.each(&:down!) }
    end
  end

  def company_actived?
    # ...
  end
end

库存(Stock)

class Stock
  belongs_to :company
  aasm :column => :state, :whiny_transitions => false do
    state :pending, :initial => true
    state :paid
    state :active

    event :pay do
      transitions :from => :pending, :to => :active, if: :company_active?
      transitions :from => :pending, :to => :paid
    end

    event :up do
      transitions :from => :paid, :to => :active, if: :company_active?
    end

    event :down do
      transitions :from => :active, :to => :paid, unless: :company_active?
    end

  end

  def company_active?
    company.active?
  end
end

经过这样的重构后整个流程变得清晰明了,只需要在适当的地方调用定义好的事件就可以了,我们的目的达到了:smile: