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?

È stato utile?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top