ActiveRecord :: Migration前缀上下文和方法

时间:2019-01-04 17:11:19

标签: ruby-on-rails ruby activerecord

我正在建立一个库来为ActiveRecord::Migration添加功能,但是我正在努力理解其行为。

加载库后,我将执行以下代码

ActiveSupport.on_load(:active_record) do
  ActiveRecord::Migration.prepend MyLibrary::Mutators
end

然后在my_library/mutators.rb

module MyLibrary
  module Mutators
    def do_something
      # do stuff here and use `self`
    end
  end
end

这里的目标非常简单,我需要能够在我的迁移类中调用此方法

class Test < ActiveRecord::Migration[5.2]
  do_something

  def change
    create_table 'async_test' do |t|
      t.string :test
    end
  end
end

运行此迁移时,它将有效地调用do_something

问题是,当我尝试获取有关运行内容的上下文时,这是我的库执行其他内容所必需的,selfActiveRecord::Migration的实例,而不是Test,但是使用此方法的类是Test

#<ActiveRecord::Migration:0x00007fac5b83df38
 @connection=nil,
 @name="ActiveRecord::Migration",
 @version=nil>

如果我改变周围的情况并在do_something中调用#change,它将把self作为Test的实例,这是我在课堂上想要的。 / p>

如何通过扩展do_something使self在班级以Test的形式返回ActiveRecord::Migration

1 个答案:

答案 0 :(得分:1)

ActiveRecord::Migration.method_missing(在类级别)调用似乎是ActiveRecord::Migration实例的nearest_delegate

 > ActiveRecord::Migration.nearest_delegate
 => #<ActiveRecord::Migration:0x0000561889aa1930 @connection=nil, @name="ActiveRecord::Migration", @version=nil>

调用ActiveRecord::Migration.prepend MyLibrary::Mutators时,您将ActiveRecord::Migration的实例方法前面加上MyLibrary::Mutators。因此do_something是在迁移实例上定义的。

致电时:

class Test < ActiveRecord::Migration[5.2]
  do_something
  # ...
end

Test.method_missing被调用,它在#do_something实例上的nearest_delegate上调用ActiveRecord::Migration

如果要在迁移类级别上真正定义do_something,则需要适当地添加类方法。在this question的答案中对此进行了精确描述。

长话短说,您应该在迁移单例类中而不是在迁移类中呼叫.prepend

ActiveSupport.on_load(:active_record) do
  ActiveRecord::Migration.singleton_class.prepend MyLibrary::Mutators
end