2010-01-06 5 views
6

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

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

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

+0

Я пытаюсь сделать очень похожую вещь. Мне жаль, что у меня не было образца кода, в котором объяснялось, как это сделать. – Andrew

ответ

17

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

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

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

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

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

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

+0

Отличный ответ, помог мне! Одна вещь, которую я задаюсь вопросом, это просто эстетика между помещением ... нового кода ... поскольку у вас есть это выше, в отличие от того, чтобы иметь что-то вроде «require Rails.root.join (« приложение »,« модели »,« пользователь ") 'в config/initializers/user_extensions.rb, а затем открыть класс и определить ... новый код ... в приложении/models/user.rb. – ilasno

1

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

Update:

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

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

+0

Обратите внимание, что эти настройки специфичны для приложения. –

Смежные вопросы