简体   繁体   中英

How to test dynamically defined methods that are based on other model

I have a model called DeviceState which contains states like "active","offline","online".

I have another model called Device which belongs_to to DeviceState .

To have methods such as @device.active? and @device.offline? on the device model, I've defined a dynamic method like so:

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

My problem is that when I try to create tests on the Device model, the dynamic method are not created because the DeviceState model hasn't been populated on the database while the test environment started up. So by the time I create the DeviceState data with factory girl, it would be too late.

One solution I tried is to seed the DeviceState in spec_helper , however while this worked for the first test it didn't work for all the rest as the database cleaner removed the data.

What would be the best way to overcome those dynamically defined methods?

As everyone pointed out in the comments, you should make the list of states static rather than dynamic based on a database table.

If you do decide to make this list static, you do the following to avoid having to write a new method every time you add a state.

app\\models\\devise.rb

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

Using a utility method that you can define in lib folder so that you can re-use it in other models if neccesary

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

Inspired by Ryan Bate's Rail Casts on state machines

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM