从外部gem扩充模型
我在我们的网站上使用refinerycms让技术水平较低的员工更新内容。 在gem中,它们有一个Page类,用于映射站点上的每个顶级页面。 我想在这个Page类上使用acts_as_taggable gem。 现在我可以将acts_as_taggle声明直接添加到page.rb文件中,但是我必须维护一个单独的git repo来跟踪我的版本和官方发行版之间的差异。
基于SO的其他一些问题,我创建了一个初始化器和扩展器,如下所示:
LIB / 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:
我第一次从服务器请求页面时,它正确输出页面上的所有标签。 但是,如果我点击刷新I而不是获得NoMethodError
表明tag_list未定义。
我是rails的新手,所以也许我的假设是错误的,但我希望对Page.send的调用会对Page类进行永久性更改,而不是对类的特定实例进行永久性更改。 那么如何在每个请求中将acts_as_taggable添加到Page类?
您需要将module_eval代码放入config.to_prepare do
块中。 最简单的方法是在config/application.rb
或创建引擎。 代码是相同的,除了它每次运行站点时执行,而不仅仅是第一次(特别是适用于开发模式)和仅在初始化过程之前执行的代码(也就是需要文件)执行到config.before_initialize do
块。
config.to_prepare
很重要的原因是因为在开发模式下,每次请求都会重新加载代码,但初始化程序通常不会。 这意味着您运行module_eval的Page
只会运行一次module_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
代码。
希望这可以帮助