0

我有一个名为的模型DeviceState,其中包含“活动”、“离线”、“在线”等状态。

我有另一个模型叫做Devicewhich belongs_toto DeviceState

为了在设备模型上使用@device.active?和之类的方法@device.offline?,我定义了一个动态方法,如下所示:

  DeviceState.all.each do |method|
    define_method((method.name + "?").to_sym) do
        self.device_state.name == method.name
    end
  end

我的问题是,当我尝试在Device模型上创建测试时,没有创建动态方法,因为DeviceState在测试环境启动时尚未在数据库中填充模型。所以当我DeviceState和工厂女孩一起创建数据时,已经太晚了。

我尝试的一个解决方案是播种DeviceStatein spec_helper,但是虽然这对第一次测试有效,但由于数据库清理器删除了数据,所以它不适用于所有其他测试。

克服那些动态定义的方法的最佳方法是什么?

4

1 回答 1

0

正如每个人在评论中指出的那样,您应该根据数据库表使状态列表静态而不是动态。

如果您决定将此列表设为静态,请执行以下操作以避免每次添加状态时都必须编写新方法。

应用\模型\设计.rb

class Devise < ActiveRecord::Base
  ...
  extend EnumFieldUtil
  enum_field :devise_state, %w[active offline online]
  ...
end

使用您可以在lib文件夹中定义的实用程序方法,以便您可以在必要时在其他模型中重新使用它

lib\enum_field_util.rb

module EnumFieldUtil
  def enum_field(field, allowed_values)
    allowed_values.each do |value|
      class_eval %Q{
        define_method("is_#{value}?") { self.#{field} == '#{value}' }
      }
    end

    class_eval %Q{
      validates_inclusion_of :#{field}, :in => #{allowed_values}, :message => "{{value}} must be in #{allowed_values.join ','}"
    }
  end
end

Ryan Bate 的 Rail Casts 在状态机上的启发

于 2013-09-16T06:37:51.460 回答