我正在构建一个向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>如果我做了一些改变,并在#change中调用do_something,它会将self视为Test的实例,这正是我希望在类级别上实现的。
如何通过扩展ActiveRecord::Migration让do_something在类级别将self作为Test返回?
发布于 2019-01-05 01:58:29
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时,您使用MyLibrary::Mutators作为ActiveRecord::Migration的实例方法的前缀。所以do_something是在迁移实例上定义的。
当你调用时:
class Test < ActiveRecord::Migration[5.2]
do_something
# ...
end调用Test.method_missing时,它在看起来是ActiveRecord::Migration实例的nearest_delegate上调用#do_something。
如果您希望在迁移类级别上真正定义do_something,则需要正确地在类方法前面加上前缀。在对this question的回答中对此进行了精确的描述。
长话短说,您应该在迁移单例类中调用.prepend,而不是在迁移类中调用:
ActiveSupport.on_load(:active_record) do
ActiveRecord::Migration.singleton_class.prepend MyLibrary::Mutators
endhttps://stackoverflow.com/questions/54043317
复制相似问题