Un modèle d'augmenter un petit bijou externe
-
26-09-2019 - |
Question
J'utilise refinerycms sur notre site pour laisser le contenu moins de mise à jour du personnel technique. A l'intérieur du bijou, ils ont une classe page qui mappe chaque page de niveau supérieur sur le site. Je voudrais utiliser la pierre précieuse acts_as_taggable sur cette classe page. Maintenant, je peux ajouter la déclaration acts_as_taggle directement au fichier page.rb, mais je dois maintenir un git distinct pour suivre les différences entre ma version et la version officielle.
Sur la base d'autres questions ici sur le SO j'ai créé un initialiseur et l'extension comme ceci:
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 %>
La première fois que je demande une page du serveur il affiche correctement toutes les balises sur la page. Cependant, si j'actualisez je hériterez d'une NoMethodError
indiquant que liste_balise est indéfini.
Je suis nouveau sur les rails alors peut-être mes suppositions sont fausses, mais je m'y attendais appel à Page.send ferait un changement permanent à la classe page plutôt que d'une instance spécifique de la classe. Alors, comment pourrais-je obtenir la acts_as_taggable ajoutée à la classe la page sur chaque demande?
La solution
Vous aurez besoin de mettre votre code module_eval dans un bloc de config.to_prepare do
. Le endroit le plus facile de le faire est en config/application.rb
ou pour créer un moteur. Le code est identique sauf qu'il exécute chaque fois que vous exécutez le site non seulement la première fois (ce qui vaut en particulier pour le mode de développement) et le code qui exécute seulement avant que le processus d'initialisation (alias nécessitant des fichiers) dans un bloc config.before_initialize do
.
La raison pour laquelle config.to_prepare
est important parce que dans le mode de développement, le code est rechargé à chaque demande, mais initializers ne sont généralement pas. Cela signifie que Page
, que vous exécutez un module_eval sur, n'aura la course module_eval une fois, mais va se recharger chaque demande. config.to_prepare
est un crochet Rails qui fonctionne à chaque fois offrant un grand confort pour des situations comme celle-ci.
approche 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
approche moteur
Si vous ne voulez pas modifier config/application.rb
alors vous pouvez, dans la raffinerie de CMS, créer vendor/engines/add_page_extensions/lib/add_page_extensions.rb
qui ressemblerait à ceci:
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
Si vous utilisez les moteurs l'approche que vous aurez besoin aussi de créer vendor/engines/add_page_extensions/add_page_extensions.gemspec
qui devrait contenir 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
Et puis dans votre Gemfile
ajouter cette ligne:
gem 'add_page_extensions', :path => 'vendor/engines'
Si vous allez l'approche du moteur, vous voudrez probablement mettre tout votre logique à l'intérieur du répertoire lib
du moteur, y compris le code Pants::Extensions::Page
.
Hope this helps