假设有一个具有 4 个状态的对象
:new
:in_process
:done
:verified
还有一种方法应该只在对象的状态大于:in_process
我该如何进行这项检查?我以为这可能是什么
def some_action
return unless my_object.state > :in_process
#do some work
end
但这只是比较字符串。
我是否遗漏了某些东西,或者是否有执行此类检查的实际方法?
谢谢。
假设有一个具有 4 个状态的对象
:new
:in_process
:done
:verified
还有一种方法应该只在对象的状态大于:in_process
我该如何进行这项检查?我以为这可能是什么
def some_action
return unless my_object.state > :in_process
#do some work
end
但这只是比较字符串。
我是否遗漏了某些东西,或者是否有执行此类检查的实际方法?
谢谢。
忽略非线性状态机的问题,我发现以下内容可以很好地满足我在一些具有简单状态机的项目中的需求:
# Check if the stage is in or before the supplied stage (stage_to_check).
def in_or_before_stage?(stage_to_check)
if stage_to_check.present? && self.stage.present?
STAGES_IN_ORDER.reverse.lazy.drop_while { |stg| stg != stage_to_check }.include?(self.stage)
else
false
end
end
有时也需要其他检查:
# 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
其中“STAGES_IN_ORDER”只是一个数组,其中的阶段按从初始到最终的顺序排列。
我们只是从列表中删除项目,然后检查对象的当前阶段是否在结果列表中。如果我们想知道它是否在某个阶段或之前,我们会删除后面的阶段,直到我们到达我们提供的测试阶段,如果我们想知道它是否在某个给定阶段之后,我们会从列表的前面删除项目。
我意识到你可能不再需要这个答案了,但希望它可以帮助某人=]
这里的问题是您在状态机内没有订单。您需要提供并声明一份。
我会坚持这个解决方案:
首先在模型中声明常量,包含状态(按顺序!),所以:
STATES = [:new, :in_process, :done, :verified]
后来,在您的模型中:
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
如果在 AASM 中定义正确的顺序并确保不覆盖任何状态(例如,指定额外的选项),则可以使用它们。
下面的 mixin 定义了 和 之类的范围Model.done_or_before
,Model.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 AASMLinearity
之后 include AASM
,但在状态机定义之前。