Дополнение модели из внешнего драгоценного камня

Я использую 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 код.

Надеюсь это поможет

Другие вопросы по тегам