从外部 gem 增强模型

发布于 2024-09-28 20:10:56 字数 1066 浏览 0 评论 0原文

我在我们的网站中使用 refinerycms 来让技术含量较低的人员更新内容。在 gem 内部,它们有一个 Page 类,用于映射站点上的每个顶级页面。我想在这个 Page 类上使用acts_as_taggable gem。现在我可以将 acts_as_taggle 声明直接添加到 page.rb 文件中,但随后我必须维护一个单独的 git 存储库来跟踪我的版本和官方版本之间的差异。

基于这里的一些其他问题,我创建了一个初始化程序和扩展,如下所示:

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

config/initializers/pants.rb

require 'page_extensions'

Page.send :include, Pants::Extensions::Page

app/views/layouts/

...
Tags: <%= @page.tag_list %>

application.html.erb服务器正确输出页面上的所有标签。但是,如果我点击刷新,我会收到一个 NoMethodError ,表明 tag_list 未定义。

我是 Rails 新手,所以也许我的假设是错误的,但我预计对 Page.send 的调用将对 Page 类而不是该类的特定实例进行永久更改。那么我如何在每个请求上将acts_as_taggable添加到Page类中呢?

I'm using refinerycms in our site to let the less technical staff update content. Inside the gem, they have a Page class that maps each top level page on the site. I'd like to use the acts_as_taggable gem on this Page class. Now I can add the acts_as_taggle declaration directly to the page.rb file, but then I'd have to maintain a separate git repo to track differences between my version and the official release.

Based on some other questions here on SO I created an initializer and extension like 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

config/initializers/pants.rb

require 'page_extensions'

Page.send :include, Pants::Extensions::Page

app/views/layouts/application.html.erb

...
Tags: <%= @page.tag_list %>

The first time I request a page from the server it correctly outputs all the tags on the page. However, if I hit refresh I instead get a NoMethodError indicating that tag_list is undefined.

I'm new to rails so perhaps my assumptions are wrong, but I expected that call to Page.send would make a permanent change to the Page class rather than to a specific instance of the class. So how would I get the acts_as_taggable added to the Page class on each request?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

停顿的约定 2024-10-05 20:10:56

您需要将 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 代码。

希望这有帮助

You will need to put your module_eval code into a config.to_prepare do block. The easiest place to do this is in config/application.rb or to create an engine. The code is identical except it executes every time you run the site not just the first time (which especially applies to development mode) and code which only executes before the initialisation process (aka requiring files) into a config.before_initialize do block.

The reason that config.to_prepare is important is because in development mode, the code is reloaded on every request but initializers generally aren't. This means that Page, which you are running a module_eval on, will only have the module_eval run once but will reload itself every request. config.to_prepare is a Rails hook that runs every single time providing great convenience for situations like this.

config/application.rb approach

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

Engine approach

If you don't want to modify config/application.rb then you can, in Refinery CMS, create vendor/engines/add_page_extensions/lib/add_page_extensions.rb which would look like this:

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

If you use the engines approach you will also need to create vendor/engines/add_page_extensions/add_page_extensions.gemspec which should contain a simple 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

And then in your Gemfile add this line:

gem 'add_page_extensions', :path => 'vendor/engines'

If you go the engine approach, you will probably want to put all of your logic inside the engine's lib directory including the Pants::Extensions::Page code.

Hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文