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.