Дополнение модели из внешнего драгоценного камня
Я использую http://refinerycms.com/ на нашем сайте, чтобы позволить менее техническому персоналу обновлять контент. Внутри драгоценного камня у них есть класс Page, который отображает каждую страницу верхнего уровня на сайте. Я хотел бы использовать гем act_as_taggable в этом классе Page. Теперь я могу добавить объявление act_as_taggle непосредственно в файл page.rb, но тогда мне придется поддерживать отдельное git-репо, чтобы отслеживать различия между моей версией и официальным выпуском.
Основываясь на некоторых других вопросах здесь, на SO я создал инициализатор и расширение следующим образом:
Библиотека /page_extensions.rb:
module Pants
module Extensions
module Page
module ClassMethods
def add_taggable
acts_as_taggable
end
end
def self.included(base)
base.extend(ClassMethods).add_taggable
end
end
end
end
конфиг / Инициализаторы /pants.rb
require 'page_extensions'
Page.send :include, Pants::Extensions::Page
приложение / просмотров / макеты /application.html.erb
...
Tags: <%= @page.tag_list %>
В первый раз, когда я запрашиваю страницу с сервера, он правильно выводит все теги на странице. Однако, если я нажму "Обновить", я получу NoMethodError
указывая, что tag_list не определен.
Я новичок в rails, так что, возможно, мои предположения неверны, но я ожидал, что вызов Page.send внесет постоянное изменение в класс Page, а не в конкретный экземпляр класса. Итак, как бы мне добавить act_as_taggable к классу Page при каждом запросе?
1 ответ
Вам нужно будет поместить свой код module_eval в config.to_prepare do
блок. Самое простое место для этого - config/application.rb
или создать двигатель. Код идентичен, за исключением того, что он выполняется каждый раз, когда вы запускаете сайт, а не только в первый раз (что особенно относится к режиму разработки) и код, который выполняется только перед процессом инициализации (так называемые файлы) в config.before_initialize do
блок.
Причина того, что config.to_prepare
Это важно, потому что в режиме разработки код перезагружается при каждом запросе, а инициализаторы обычно - нет. Это означает, что Page
, на котором вы запускаете module_eval, модуль_eval будет запускаться только один раз, но будет перезагружаться при каждом запросе. config.to_prepare
является хуком Rails, который запускается каждый раз, обеспечивая большое удобство в подобных ситуациях.
подход config / application.rb
class Application < Rails::Application
# ... other stuff ...
config.before_initialize do
require 'page_extensions'
end
config.to_prepare do
Page.send :include, Pants::Extensions::Page
end
end
Подход двигателя
Если вы не хотите изменять config/application.rb
затем вы можете в Refinery CMS создать vendor/engines/add_page_extensions/lib/add_page_extensions.rb
который будет выглядеть так:
require 'refinery'
module Refinery
module AddPageExtensions
class Engine < Rails::Engine
config.before_initialize do
require 'page_extensions'
end
config.to_prepare do
Page.send :include, Pants::Extensions::Page
end
end
end
end
Если вы используете подход двигателей, вам также нужно будет создать vendor/engines/add_page_extensions/add_page_extensions.gemspec
который должен содержать простой gemspec:
Gem::Specification.new do |s|
s.name = 'add_page_extensions'
s.require_paths = %w(lib)
s.version = 1.0
s.files = Dir["lib/**/*"]
end
И тогда в вашем Gemfile
добавьте эту строку:
gem 'add_page_extensions', :path => 'vendor/engines'
Если вы подходите к движку, вы, вероятно, захотите поместить всю свою логику в двигатель. lib
каталог, включая Pants::Extensions::Page
код.
Надеюсь это поможет