8

Sono in procinto di aggiornare un'applicazione Rails 3 per utilizzare Rails 3.1 e, come parte di questo, sto facendo uso della nuova pipeline di asset. Finora, ho tutto a parte un problema piuttosto fastidioso che non riesco a risolvere.Risorse precompilate interrotte in Rails 3.1 durante la distribuzione su un URI secondario

L'applicazione e tutti i suoi asset funzionano correttamente nello sviluppo, ma in produzione viene distribuita a un sub-URI utilizzando Passenger (http://the-host/sub-uri/). Il problema con questo è che le risorse sono precompilate durante l'implementazione e uno dei miei file CSS (beh, è ​​un file .css.scss) utilizza l'helper . Dal momento che durante il processo di pre-compilazione, i percorsi sono hard-coded nel file CSS precompilato, il sub-uri non è presa in considerazione:

Nel mio file .css.scss:

body { background-image: image-url("bg.png"); } 

Il risultato nel compilato application-<md5-hash-here>.css di file:

body { background-image: url(/assets/bg.png); } 

quello che dovrebbe essere per farlo funzionare correttamente:

body { background-image: url(/sub-uri/assets/bg.png); } 

Questo scenario richiede troppo? Se è così, dovrò tornare al vecchio modo non asset-pipeline e servirmi solo le mie immagini e i CSS da public. Tuttavia sembra qualcosa che avrebbe dovuto essere pensato e risolto ...? Mi manca la soluzione?


Edit 1: Vorrei sottolineare che con il erb solution produce invece lo stesso risultato, come ci si aspetterebbe.


Edit 2: in risposta al commento di Benoit Garret

No, il problema non è legato alla config.assets.prefix. Ho provato a impostare quello (a /sub-uri/assets anziché il valore predefinito di /assets) ma è risultato che era la cosa sbagliata da fare: sembra che questa impostazione sia già in relazione con la radice dell'app Rails, non con il server. La rimozione (e quindi il ritorno al default) ha risolto tutti i problemi strani che hanno causato (e ce ne sono stati molti, tutti gli asset sono finiti nello /sub-uri/sub-uri/assets - era tutto molto strano). L'unico problema è che l'helper e gli amici image-url non raccolgono l'URI secondario quando sono precompilati. Inutile dire che questo è logico dal momento che, quando è precompilato, non può sapere che quando è in esecuzione su Passenger, verrà configurato in questo modo. La mia domanda è come informarla di questo e quindi finire con i percorsi corretti nel risultato precompilato. Se davvero si può fare.

La mia soluzione attuale consiste nel fare riferimento all'liamge nel CSS in questo modo: url(../images/bg.png) e posizionarlo nella posizione public/images non in pipeline. Difficilmente ideale in quanto non beneficia delle impronte digitali e di tutto ciò che fornisce la pipeline.

+0

Hai provato questo? http://stackoverflow.com/questions/7295744/how-to-deploy-rails-3-1-app-in-a-subdirectory –

+0

L'app stessa viene distribuita correttamente (utilizza il metodo RailsBaseURI poiché è ciò che i passeggeri i documenti raccomandano). Tutte le risorse collegate da all'interno dell'applicazione in esecuzione come le immagini che usano 'image_tag' e così via vanno bene. l'unico problema sono le immagini a cui si fa riferimento all'interno del CSS - non conosce il sub-URI al momento della pre-compilazione delle risorse. È quello per cui ho bisogno di una soluzione se ce n'è una. –

+0

Quindi il tuo problema è che l'helper 'image-uri' non rileva' config.assets.prefix'? –

risposta

4

Infine ho elaborato un paio di soluzioni alternative.

1) Da https://github.com/rails/sass-rails/issues/17 sembra che questo potrebbe essere corretto in sass-rail. Ho aiutato gli helper con le patch della scimmia seguendo le linee della patch proposta nel link qui sopra.Ho semplicemente impostato la variabile di ambiente richiesta nella riga di precompilazione asset in deploy.rb.

Faccio tutte le patch della mia scimmia in un singolo file config/initializers/gem_patches.rb. In questo file patchato questo metodo come:

module Sass 
    module Rails 
    module Helpers 
     protected 
     def public_path(asset, kind) 
     path = options[:custom][:resolver].public_path(asset, kind.pluralize) 
     path = ENV['PRODUCTION_URI'] + path if ENV['PRODUCTION_URI'] 
     path 
     end 
    end 
    end 
end 

2) In alternativa, se stai bene di inserire delle immagini nel CSS, cambiando il foglio di stile per avere un'estensione .erb, e la sostituzione del image-url("bg.png") con url(<%= asset_data_uri "bg.png" %>) funzionerà senza alcun bisogno di cambiare sass-rails. asset-data-uri non esiste come pura funzione Sass, quindi devi usare l'helper Rails asset_data_uri.

+0

Buon urlo sul secondo punto: funzionerebbe ed è qualcosa che non ho mai considerato. Decisamente meno desiderabile, ma una soluzione valida. Per il punto 1, potresti chiarire l'impostazione della variabile in 'deploy.rb' per favore? –

+0

Ho appena capito cosa intendi ... stai eseguendo manualmente l'attività precompilata dal tuo file deploy.rb, giusto? Sto usando quello fornito aggiungendo 'load 'deploy/assets'' al mio Capfile - quindi non c'è nulla di ovvio in' deploy.rb' dove dovrei mettere le impostazioni della variabile d'ambiente. Sono sicuro di poter trovare da qualche altra parte per impostarlo però. Anche nel peggiore dei casi, mi hai dato un problema da tenere d'occhio, nella migliore delle ipotesi penso che sia la risposta per adesso. Grazie :) –

+0

Esattamente. Nel mio 'deploy.rb' ho il precompilare l'asset in un'attività' dopo 'deploy: update_code "'. Eseguo "esegui" cd # {release_path}; raggruppa le risorse rake exec: precompila RAILS_ENV = production PRODUCTION_URI = '/ myapp' "' e poi nei miei helper patch-scimmia.rb, prendo semplicemente 'ENV ['PRODUCTION_URI']' . –

0

Dopo aver scavato un po ', ho trovato il problema. Il problema è in Rails, in particolare Sprockets :: Helpers :: RailsHelper :: AssetPaths # compute_public_path. Pignoni :: Helpers :: RailsHelper :: AssetPaths eredita da ActionView :: AssetPaths e sovrascrive un numero di metodi. Quando compute_public_path viene chiamato tramite il metodo Sass :: Rails :: Resolver # public_path è sass-rails, l'helper pignone rails preleva l'attività di risoluzione della risorsa. Pignoni :: Helpers :: RailsHelper :: AssetPaths # compute_public_path fa riferimento a super che è ActionView :: AssetPaths # compute_public_path. In questo metodo c'è una condizione di ha_request? su rewrite_relative_url_root come si vede qui sotto:

def compute_public_path(source, dir, ext = nil, include_host = true, protocol = nil) 
    ... 
    source = rewrite_relative_url_root(source, relative_url_root) if has_request? 
    ... 
end 

def relative_url_root 
    config = controller.config if controller.respond_to?(:config) 
    config ||= config.action_controller if config.action_controller.present? 
    config ||= config 
    config.relative_url_root 
end 

Se si guarda la struttura interna di rewrite_relative_url_root si basa su una richiesta di essere presenti e la capacità di derivare dalla variabile di controllo al fine di risolvere alla radice URL relativo. Il problema è che quando i pignoni risolvono queste risorse per sass, non ha un controller presente e quindi nessuna richiesta.

La soluzione di cui sopra non ha funzionato in modalità di sviluppo per me. Ecco la soluzione che sto usando per farlo funzionare per ora:

module Sass 
    module Rails 
    module Helpers 
     protected 
     def public_path(asset, kind) 
     resolver = options[:custom][:resolver] 
     asset_paths = resolver.context.asset_paths 
     path = resolver.public_path(asset, kind.pluralize) 
     if !asset_paths.send(:has_request?) && ENV['RAILS_RELATIVE_URL_ROOT'] 
      path = ENV['RAILS_RELATIVE_URL_ROOT'] + path 
     end 
     path 
     end 
    end 
    end 
end 
+0

Ho ragione nel pensare che questa è essenzialmente la stessa correzione dell'altra risposta, ma implementata solo Poco diversamente? (forse un po 'meno ingenuamente, non che l'altro approccio mi abbia causato problemi ...) –

+0

https://github.com/rails/rails/pull/2977 –

2

Negli ultimi Rails 3.1.3 è necessario scimmia rattoppare un modulo diverso ora, per farlo funzionare

Questo è ciò che ho fatto

module Sprockets 
    module Helpers 
    module RailsHelper 

     def asset_path(source, options = {}) 
     source = source.logical_path if source.respond_to?(:logical_path) 
     path = asset_paths.compute_public_path(source, asset_prefix, options.merge(:body => true)) 
     path = options[:body] ? "#{path}?body=1" : path 
     if !asset_paths.send(:has_request?) 
      path = ENV['RAILS_RELATIVE_URL_ROOT'] + path if ENV['RAILS_RELATIVE_URL_ROOT'] 
     end 
     path 
     end 

    end 
    end 
end 

e nella mia deploy.rb ho:

desc "precompile the assets" 
namespace :assets do 
    task :precompile_assets do 
    run "cd #{release_path} && rm -rf public/assets/* && RAILS_ENV=production bundle exec rake assets:precompile RAILS_RELATIVE_URL_ROOT='/my_sub_uri'" 
    end 
end 
before "deploy:symlink", "assets:precompile_assets" 
+3

grazie. e ho scoperto che in Rails 3.2 non abbiamo bisogno della patch. basta eseguire il comando 'bundle exec rake assets: precompilare RAILS_RELATIVE_URL_ROOT = '/ my_sub_uri'" 'e funziona –

+0

Grazie a @SiweiShen, per capistrano ho aggiunto un'attività in deploy.rb da eseguire prima della distribuzione: assets: precompilare, che ha fatto 'set: asset_env, "# {asset_env} RAILS_RELATIVE_URL_ROOT =/my_sub_uri" ' – Cam

2

sto usando Rails 3.1.3 e la distribuzione su un su b-URI con successo. Non ho nulla di scimmia.

I problemi principali di questa configurazione sono stati discussi meglio here. Come puoi vedere, la soluzione è stata applicata a Rails 3.2 e mai backPorted a 3.1.4.

Ma, sono arrivato a una soluzione utilizzando Rails 3.1.3 che funziona per la mia configurazione.

Prova questo:(io non sono esperto, solo cercando di contribuire a risolvere un problema che mi disturbino per ore ...)

environment.rb:

#at top: 
ENV['RAILS_RELATIVE_URL_ROOT'] = '/rais' 

produzione.RB:

config.assets.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] ? ENV['RAILS_RELATIVE_URL_ROOT'] + '/assets' : '/assets' 

routes.rb:

Rais::Application.routes.draw do 
     scope ENV['RAILS_RELATIVE_URL_ROOT'] || '/' do #see config/environment.rb 
      <<resources here>> 
     end 
    end 

Come potete vedere, ho messo dentro assets.prefix production.rb, non in application.rb Dopo che si fa:

rake assets:clear 
rake assets:precompile 

e rispetto, test con la console:

RAILS_ENV=production rails console 

Risultati:

foo = ActionView::Base.new 
foo.stylesheet_link_tag 'application' 
=> "<link href=\"/rais/assets/layout.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"/rais/assets/application.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />" 
foo.image_tag('arrow-up.png') 
=> "<img alt=\"Arrow-up\" src=\"/rais/assets/arrow-up-ca314ad9b991768ad2b9dcbeeb8760de.png\" />"