Adding a method to a Rails ActiveRecord class
In plain Ruby, this works just fine:
class TestSuper
def foo
puts "In TestSuper.foo"
end
end
class TestClass < TestSuper
def foo
开发者_开发问答 super
puts "In TestClass.bar"
end
end
class TestClass
def bar
puts "In TestClass.bar, second definition"
puts "Calling foo:"
foo
end
end
t = TestClass.new
t.foo
t.bar
I can call foo() and bar() on a TestClass instance and get exactly what I expect:
In TestSuper.foo
In TestClass.bar
In TestClass.bar, second definition
Calling foo:
In TestSuper.foo
In TestClass.bar
However, when I try something very similar in a Rails migration, I get errors:
#### my_model.rb ####
puts "In my_model.rb"
class MyModel
has_many :foo
end
#### my_migration.rb ####
puts "In my_migration.rb"
class MyModel
def bar
foo.each{ |f| f.baz }
end
end
class MyMigration < ActiveRecord::Migration
def self.up
MyModel.find(1).bar
end
def self.down
# Not applicable
end
end
The first problem is that MyModel.find() disappears unless I explicitly have it extend ActiveRecord in my_migration.rb. Otherwise, it drops the superclass.
If I do that, I then get an error on the foo
call in MyModel.bar().
If I comment out the class (re)definition in my_migration.rb, find() and bar() both work just fine.
During the course of my debugging, I added the puts
statements to see when each file & class was being executed. It appears that my_model.rb doesn't even get loaded if MyModel is already defined (which I'm doing in my_migration.rb).
So: why does this happen in Rails, and how can I work around it?
theory #2: at the top of your migration
require 'app/models/my_model'
You need to reference a constant for your model first, that will load your model class. Then you can alter that class. The following are 3 ways of doing the same thing:
MyModel class MyModel def bar foo.each{ |f| f.baz } end end
MyModel.module_eval do def bar foo.each{ |f| f.baz } end end
MyModel.send :include, Module.new { def bar foo.each{ |f| f.baz } end }
in your example i think you're missing
< ActiveRecord::Base
from your first definition.
in your migration monkey patch you also need a matching
< ActiveRecord::Base
the two class definitions have to match
精彩评论