Расширение ruby ​​gem в Rails

Допустим, у меня есть приложение Rails, которое получает большую часть своей функциональности от драгоценного камня (например, CMS).

Если мне теперь нужно добавить некоторые настройки (например, добавить свойство для пользователя), как лучше всего это сделать? Если я настрою драгоценный камень, у меня будут проблемы с обновлением драгоценного камня в будущем.

Каков наилучший подход здесь?


person Neil Middleton    schedule 06.01.2010    source источник
comment
Я пытаюсь сделать очень похожую вещь. Хотелось бы, чтобы у меня был пример кода, объясняющий, как это сделать.   -  person Andrew    schedule 25.11.2010


Ответы (2)


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

Я не буду вдаваться в подробности, но вы действительно хотите поместить свои расширения в инициализатор или гем, поскольку они перезагружаются между запросами в режиме разработки. Если вы поместите код в плагин, он не будет перезагружен, и вы получите очень загадочные ошибки, такие как «Копия XXX была удалена из дерева модулей, но все еще активна!»

Проще всего кинуть код в инициализатор (например, config/initializers/user_extensions.rb). Вы можете просто использовать class_eval для ввода кода.

User.class_eval do
  ... new code ...
end

Одним из основных недостатков расширяемости ruby ​​является отслеживание источника кода. Возможно, вы захотите добавить какое-нибудь сообщение в журнал о загружаемых расширениях, чтобы люди могли его отследить.

Rails.logger.info "\n~~~ Loading extensions to the User model from #{ __FILE__ }\n"
User.class_eval do
  ... new code ...
end

Дальнейшее чтение:

http://airbladesoftware.com/notes/monkey-patching-a-gem-in-rails-2-3

person James H    schedule 05.01.2011
comment
Отличный ответ, помог мне! Мне интересно, является ли это просто эстетикой между размещением... нового кода... как у вас выше, в отличие от чего-то вроде «требовать Rails.root.join(приложение, модели, пользователь)» в config/ initializers/user_extensions.rb, а затем открыть класс и определить... новый код... в app/models/user.rb. - person ilasno; 27.04.2012

Ruby позволяет вам расширять классы во время выполнения, поэтому вы часто можете взломать библиотеку, не касаясь исходного кода. В противном случае я бы посоветовал вам загрузить гем, создать несколько хуков в библиотеке и отправить их обратно в качестве патча.

Обновление:

Обратите внимание, что эти настройки зависят от приложения.

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

person troelskn    schedule 06.01.2010
comment
Обратите внимание, что эти настройки зависят от приложения. - person Neil Middleton; 06.01.2010