Ever wanted to undefine a class in ruby and reload it afterwards? Needed this as I wanted to restart a test suite with the models using table names - tests for the has_many_polymorphs plugin. It’s a dirty hack and doesn’t work with instantiated fixtures, but at least it makes shure the same tests run on models with table_name set.
To “reload a class” you unset the class constant in the main object name space and then reload the class source file. In my case I wanted the table name to be set before the association creation macros (has_many, belongs_to etc.) are called, so they use the correct table name.
This works by unsetting the class constant, then recreating the class manually by setting the class name constant to the newly created class, setting the table name and afterwards loading the model file, enhancing the class we created before with the table name already set.
class PolymorphTableTest < PolymorphTest
fixtures :test_petfoods, :test_cats, :test_dogs, :test_wild_boars
CLASSES = [:Cat, :Dog, :EatersParent, :WildBoar, :Kitten, :Tabby, :Petfood]
def setup
names = CLASSES
# unset classes
Object.class_eval do
names.each do |clazz|
remove_const clazz.to_s if const_defined? clazz.to_s
end
end
# create new and set table names
[:Dog, :Cat, :WildBoar, :EatersParent, :Petfood].each do |name|
Object.class_eval do
clazz = const_set(name.to_s, Class.new(ActiveRecord::Base))
clazz.set_table_name "test_#{name.to_s.pluralize.underscore}"
end
end
# reload model files
names.each do |clazz|
load "#{clazz.to_s.underscore}.rb"
end
super
end
def teardown
super
names = CLASSES
# unset model classes
Object.class_eval do
names.each do |clazz|
remove_const clazz.to_s if const_defined? clazz.to_s
end
end
# reload model files
names.each do |clazz|
load "#{clazz.to_s.underscore}.rb"
end
end
end