Aumentare un modello da un gioiello esterna
-
26-09-2019 - |
Domanda
refinerycms nel nostro sito per lasciare che il contenuto di meno tecnico di aggiornamento del personale. All'interno della gemma, hanno una classe di pagina che mappa ogni pagina di livello superiore del sito. Mi piacerebbe usare la gemma acts_as_taggable su questa pagina di classe. Ora posso aggiungere la dichiarazione acts_as_taggle direttamente al file page.rb, ma poi avrei dovuto mantenere un repo git separato per tenere traccia delle differenze tra la mia versione e il rilascio ufficiale.
Sulla base di alcune altre domande qui su così ho creato un inizializzatore e l'estensione in questo modo:
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 / inizializzatori / pants.rb
require 'page_extensions'
Page.send :include, Pants::Extensions::Page
app / views / layout / application.html.erb
...
Tags: <%= @page.tag_list %>
La prima volta che chiedo una pagina dal server emette correttamente tutti i tag sulla pagina. Tuttavia, se ho colpito aggiornare io invece ottenere un NoMethodError
che indica che tag_list è indefinito.
Sono nuovo di rotaie così forse le mie supposizioni sono sbagliate, ma mi aspettavo che sarebbe chiamata a Page.send apportare una modifica permanente alla classe Page, piuttosto che ad una specifica istanza della classe. Così come faccio a ottenere l'acts_as_taggable aggiunto alla classe pagina su ogni richiesta?
Soluzione
Sarà necessario inserire il codice module_eval in un blocco config.to_prepare do
. Il posto più facile per farlo è in config/application.rb
o per creare un motore. Il codice è identico tranne che esegue ogni volta che si esegue il sito non è solo la prima volta (che vale soprattutto per la modalità di sviluppo) e il codice che viene eseguito solo prima che il processo di inizializzazione (file alias richiedono) in un blocco config.before_initialize do
.
La ragione per cui config.to_prepare
è importante è perché in modalità di sviluppo, il codice viene ricaricato su ogni richiesta, ma in generale non sono inizializzatori. Ciò significa che Page
, che si esegue un module_eval in poi, avrà solo la corsa module_eval una volta, ma sarà ricaricata in sé ogni richiesta. config.to_prepare
è un gancio Rails che viene eseguito ogni volta che fornisce grande convenienza per situazioni come questa.
config / application.rb avvicinarsi
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
approccio motore
Se non si desidera modificare config/application.rb
allora si può, in Raffineria CMS, creare vendor/engines/add_page_extensions/lib/add_page_extensions.rb
che sarebbe simile a questa:
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
Se si utilizzano i motori di approccio sarà anche necessario creare vendor/engines/add_page_extensions/add_page_extensions.gemspec
che dovrebbe contenere una semplice 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
E poi nel vostro Gemfile
aggiungere la seguente riga:
gem 'add_page_extensions', :path => 'vendor/engines'
Se si va l'approccio del motore, probabilmente si vuole mettere tutta la tua logica all'interno directory lib
del motore compreso il codice Pants::Extensions::Page
.
Spero che questo aiuti