我正在建立一个库来为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
问题是,当我尝试获取有关运行内容的上下文时,这是我的库执行其他内容所必需的,self
是ActiveRecord::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
?
答案 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