ActiveRecord :: Контекст и метод предварительного переноса миграции - PullRequest
0 голосов
/ 04 января 2019

Я создаю библиотеку, чтобы добавить функциональность к 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, что мне бы хотелось на уровне класса.

Как я могу получить do_something, чтобы вернуть self как Test на уровне класса, увеличив ActiveRecord::Migration?

1 Ответ

0 голосов
/ 04 января 2019

ActiveRecord::Migration.method_missing (на уровне класса) вызывает nearest_delegate, который выглядит как экземпляр ActiveRecord::Migration

 > 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 на уровне класса миграции, вам нужно правильно добавить методы класса. Это точно описано в ответах на этот вопрос .

Короче говоря, вы должны вызывать .prepend в классе синглтона миграции, а не в классе миграции:

ActiveSupport.on_load(:active_record) do
  ActiveRecord::Migration.singleton_class.prepend MyLibrary::Mutators
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...