Magnification of the model from an external stone

I use refinerycms on our website to reduce the maintenance of technical staff. Inside the gem, they have a page class that displays each top-level page on the site. I would like to use act_as_taggable gem in this class. Now I can add the act_as_taggle declaration directly to the page.rb file, but then I will have to maintain a separate git repository to track the differences between my version and the official version.

Based on some other questions here in SO, I created an initializer and extension as follows:

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 

configurations / Initializers / pants.rb

 require 'page_extensions' Page.send :include, Pants::Extensions::Page 

application / views / layouts / application.html.erb

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

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

I am new to rails, so maybe my assumptions are wrong, but I expected that calling on page.send would result in a permanent change to the page class, and not to a specific instance of the class. So, how can I get act_as_taggable added to the page class for each request?

+6
ruby metaprogramming refinerycms
source share
1 answer

You need to add the module_eval code to the config.to_prepare do block. The easiest way to do this is in config/application.rb or create an engine. The code is identical, except that it is executed every time you launch the site not only for the first time (which especially applies to the development mode), and the code that is executed only before the initialization process (aka requiring files) is in the config.before_initialize do block config.before_initialize do .

The reason config.to_prepare is important is because in development mode the code reloads on every request, but initializers are usually missing. This means that the Page in which you use module_eval will only work once the eval_module, but will reload every request. config.to_prepare is a Rails hook that runs every time, providing convenience for such situations.

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 

Engine approach

If you do not want to change config/application.rb , you can create vendor/engines/add_page_extensions/lib/add_page_extensions.rb in CASE for a refinery, which will 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 vendor/engines/add_page_extensions/add_page_extensions.gemspec approach, you 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 move on to approaching the engine, you probably want to put all your logic in the lib engine directory, including the Pants::Extensions::Page code.

Hope this helps

+14
source share

All Articles