检查状态是否已超过aasm中的另一个状态?

时间:2014-10-31 21:43:28

标签: ruby-on-rails aasm

假设有一个具有4个状态的对象

:new
:in_process
:done
:verified

还有一种方法只应在对象处于大于:in_process

的状态时执行

我该怎么做这个检查?我认为这可能是某种东西

def some_action
  return unless my_object.state > :in_process
  #do some work
end

但这只是比较字符串。

我是否遗漏了某些内容,或者是否有实际执行此类检查的方法?

感谢。

3 个答案:

答案 0 :(得分:2)

忽略非线性状态机的问题,我发现以下内容可以很好地满足我对一些使用简单状态机的项目的需求:

# Check if the stage is in or after the supplied stage (stage_to_check).
def in_or_after_stage?(stage_to_check)
  if stage_to_check.present? && self.stage.present?
    # Get all the stages that are in and after the stage we want to check (stage_to_check),
    # and then see if the stage is in that list (well, technically in a lazy enumerable).
    STAGES_IN_ORDER.lazy.drop_while { |stg| stg != stage_to_check }.include?(self.stage)
  else
    false
  end
end

并且有时也需要另一项检查:

                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
             InputStream caInput = getResources().openRawResource(R.drawable.cert);
             Certificate ca;
             try {
                 ca = cf.generateCertificate(caInput);
                 System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
             } finally {
                 caInput.close();
             }
             String keyStoreType = KeyStore.getDefaultType();
             KeyStore keyStore = KeyStore.getInstance(keyStoreType);
             keyStore.load(null, null);
             keyStore.setCertificateEntry("ca", ca);
             String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
             TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
             tmf.init(keyStore);
             SSLContext context = SSLContext.getInstance("TLS");
             context.init(null, tmf.getTrustManagers(), null);
            mRequestQueue =Volley.newRequestQueue(getApplicationContext(), new HurlStack(null, context.getSocketFactory()));

" STAGES_IN_ORDER"只是一个从初始到最终按顺序排列的数组。

我们只是从列表中删除项目,然后检查我们对象的当前阶段是否在我们的结果列表中。如果我们想知道它是在某个阶段之前还是之前,我们会删除后面的阶段,直到我们到达我们提供的测试阶段,如果我们想知道它是否在某个给定阶段之后我们从前面移除了项目列表。

我意识到你可能不再需要这个答案,但希望它可以帮助某人=]

答案 1 :(得分:0)

这里的问题是你没有在状态机内部订购。您需要提供并声明一个。

我会坚持这个解决方案:

  1. 首先在模型中声明常量,包含状态(按顺序!),所以: STATES = [:new, :in_process, :done, :verified]

  2. 之后,在您的模型中:

  3. def current_state_index
      return state_index(self.state)
    end
    
    def state_index(state)
      return STATES.index(state)
    end
    
    def some_action
      return unless current_state_index > state_index(:in_process)
      #do some work end
    end
    

答案 2 :(得分:0)

如果需要注意在AASM中定义正确的顺序并确保覆盖任何状态(例如,指定额外选项),则可以使用它们。

以下mixin定义了Model.done_or_beforeModel.in_process_or_after等范围,以及m.done_or_before?等方法。

module AASMLinearity
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def aasm(*args, &block)
      r = super(*args, &block)
      if block
        states = r.state_machine.states.map(&:name)
        column = r.attribute_name
        states.each_with_index do |state, i|
          scope "#{state}_or_after", ->{ where(column => states[i..-1]) }
          scope "#{state}_or_before", ->{ where(column => states[0..i]) }

          define_method "#{state}_or_after?", ->{ states[i..-1].include? read_attribute(column).to_sym }
          define_method "#{state}_or_before?", ->{ states[0..i].include? read_attribute(column).to_sym }
        end
      end
      r
    end
  end
end

您可以在 app/models/concerns/aasm_linearity.rb之后但在状态机定义之前将其放在include AASMLinearityinclude AASM 之类的内容中。