Как расширить "незагружаемый" 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 ответа:
Конфигурация 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
вещи; может быть, я спрашиваю что-то очевидное, но-вы пробовали сделать свой модуль расширения не загружаемым, тоже? (Вам это не понадобится, если вы обезьянничали с модулем вместо того, чтобы создать новый)