开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜