Как расширить "незагружаемый" Rails плагин?


Я пытаюсь написать плагин, который будет расширятьInheritedResources .

В частности, я хочу переписать некоторые помощники по умолчанию.

И я хотел бы, чтобы он "просто работал" после установки, без каких-либо изменений в коде приложения.

Функциональность обеспечивается в модуле, который должен быть включен в нужное место . Вопрос в том, где именно? :)

Первая попытка была сделать это в init моего плагина.РБ:

InheritedResources::Base.send :include, MyModule

Он работает в производстве, но терпит неудачу неудачно в разработке, так как InheritedResource:: Base объявлен как unloadable и поэтому его код перезагружается при каждом запросе. Так что мой модуль там для первого запроса, а потом его не стало.

InheritedResource:: Base снова "втягивается" любым контроллером, который его использует:

Class SomeController < InheritedResource::Base

Но ни один код не "тянет" мой модуль расширения, так как он не ссылается нигде, кроме init.rb, который не повторно загружается по каждому запросу

Так что прямо сейчас я просто включаю модуль вручную в каждом контроллере, который нуждается в этом, который сосет. Я даже не могу включить его один раз в ApplicationController, потому что InheritedResources наследует от него, и поэтому он будет переопределять любые изменения обратно.

Обновление

Я не ищу советов о том, как "обезьянничать". Расширение работает в производстве просто великолепно. моя проблема заключается в том, как поймать момент точно после загрузки InheritedResources, чтобы вставить в него мое расширение:)

Update2

Еще одна попытка уточнение:

Последовательность событий

  • a) rails загружает Плагины. мой плагин загружается после inherited_resources и исправляет его.
  • b) запрос режима разработки подается и работает
  • c) rails выгружает Весь "не загружаемый" код, который включает в себя весь код приложения, а также inherited_resources
  • d) поступает еще один запрос
  • e) rails загружает контроллер, который наследует от унаследованных ресурсов
  • f) унаследованные нагрузки рельсов ресурсы, которые наследуются от application_controller
  • g) rails загружает application_contrller (или может быть его уже загрузили на этом этапе, не уверен)
  • g) запрос не выполняется, так как никто не загружал мой плагин для исправления inherited_resources. плагин init.файлы rb не перезагружаются

Мне нужно поймать точку во времени между g и h

2 3

2 ответа:

Конфигурация Rails::, config в файлах среды позволяет регистрировать обратный вызов диспетчера, который выполняется перед каждым запросом в режиме разработки или один раз, когда он находится в рабочем режиме.

config.to_prepare do
   # do something here
end

Проблема в том, что я не думаю, что ваш плагин имеет доступ к config, когда init.файл RB двиг. Вот способ зарегистрировать обратный звонок непосредственно в диспетчерской. Просто положи это в инит.файл rb.

require 'dispatcher'
::Dispatcher.to_prepare do
    puts "hi there from a plugin"
end
Предупреждение: я не знаю, какие побочные эффекты это может иметь. Если возможно, попытаться получить доступ к config и зарегистрировать обратный вызов правильным способом.

То, что вы пытаетесь сделать, обычно называется "MonkeyPatch" - изменение способа работы одного модуля или класса путем "переопределения" методов.

Это обычная практика в Rails, но это не означает, что это лучший способ сделать что - то-когда это возможно, лучше использовать общее наследование (это более явно о вносимых изменениях).

Что касается ваших вопросов о том, "куда поместить файлы": обычно это lib/ каталог. Это может означать lib приложения rails, или lib каталог внутри драгоценного камня или плагина, если вы в этом разбираетесь.

Например, если файл, который вы хотите изменить, является lib/generators/rails/templates/controller.rb унаследованных ресурсов, первое, что вам нужно сделать, это скопировать эту структуру каталогов внутри вашей lib/ папки ('lib/generators/rails/templates/controller.rb')

Внутри вашего нового файла (пустого в начале) вы можете переопределить методы. Однако вы также должны иметь иерархию модулей/классов. Так, если исходный камень был это:

module foo
  module bar
    def f1
    ...
    end
    def f2
    ...
    end
  end
  def f3
  ...
  end
end

И вы хотели бы изменить f1, вы должны были бы уважать модули foo-bar.

module foo
  module bar
    def f1
    ... # your code here
    end
  end
end

Теперь последнее, что вам нужно, это убедиться, что этот код выполняется в нужное время. Если вы используете lib/ папку приложения, вам нужно будет создать запись в папке initializers/ и require вашего нового файла. Если вы разрабатываете gem / плагин, у вас будет init.rb-файл в "корневой" папке этого плагина. Поставьте там "require".

Я не очень хорошо знаком с этим unloadable вещи; может быть, я спрашиваю что-то очевидное, но-вы пробовали сделать свой модуль расширения не загружаемым, тоже? (Вам это не понадобится, если вы обезьянничали с модулем вместо того, чтобы создать новый)