Il modo migliore per aggiungere JavaScript specifici per la pagina in un'app Rails 3?


159

Rails 3 ha un discreto JavaScript che è piuttosto interessante.

Ma mi chiedevo quale sia il modo migliore per includere JavaScript aggiuntivo per una determinata pagina.

Ad esempio, dove in precedenza avrei potuto fare:

<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>

Ora possiamo renderlo discreto con qualcosa del genere

<%= f.radio_button :rating, 'positive' %>

# then in some other file
$('user_rating_positive').click(function() {
  $('some_div').show();
}

Quindi immagino che la mia domanda sia dove / come includere quel JavaScript? Non voglio riempire il application.jsfile perché questo JavaScript è applicabile solo a questa vista. Dovrei includere un file JavaScript personalizzato per ogni pagina in qualche modo o incollarlo in una variabile di istanza che l'intestazione cerca?



Per coloro che desiderano una piena comprensione di come funziona e di cosa è meglio leggere railsapps.github.io/rails-javascript-include-external.html . Questa è di gran lunga la migliore documentazione che ho visto su questo argomento. È un'ottima lettura non solo per Rails ma per tutti coloro che si occupano di sviluppo web. Ecco perché è meglio fare le cose nel modo giusto. Sicuramente userò Unholy Rails per le mie domande future. WOW.
DutGRIFF,

2
@KateGregory che uno è più recente.
Ciro Santilli 14 冠状 病 六四 事件 法轮功

Risposte:


153

Quello che mi piace fare è includere il Javascript per visualizzazione in un content_for :headblocco e quindi yieldin quel blocco nel layout dell'applicazione. Per esempio

Se è piuttosto corto, allora:

<% content_for :head do %>
  <script type="text/javascript">
    $(function() {
      $('user_rating_positve').click(function() {
        $('some_div').show();
      }
    });
  </script>
<% end %>

o, se più a lungo, quindi:

<% content_for :head do %>
  <script type="text/javascript">
    <%= render :partial => "my_view_javascript"
  </script>
<% end %>

Quindi, nel tuo file di layout

<head>
  ...
  <%= yield :head %>
</head>

40
Perché non usare il <%= javascript_include_tag "my_javascipt_file" %> ?
AJP,

5
@AJP Immagino che sconfigge lo scopo della pipeline di attività
lulalala

2
@lulalala ma il codice nella risposta non lo fa comunque ma in modo più disordinato?
AJP

8
@AJP è più complicato, ma ha una richiesta http in meno da fare rispetto alla tua risposta.
Lulalala,


103

Se vuoi includere javascript solo in una pagina, puoi ovviamente includerlo nella pagina in linea, tuttavia se vuoi raggruppare il tuo javascript e sfruttare la pipeline di risorse, js minimizzati ecc., È possibile farlo e avere extra risorse js che vengono combinate e caricate solo su pagine specifiche suddividendo le js in gruppi che si applicano solo in determinati controller / viste / sezioni del sito.

Sposta i tuoi js nelle risorse in cartelle, con un file manifest separato per ciascuno, quindi se avessi una libreria js admin che viene utilizzata solo sul back-end, potresti farlo:

  • risorse
    • javascript
      • Admin
        • ... js
      • admin.js (manifest per il gruppo admin)
      • application.js (manifest per il gruppo globale dell'app)
      • globale
        • ... js

nell'applicazione.js esistente

//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder

in un nuovo file manifest admin.js

//= require_tree ./admin // requires all js files in admin folder

Assicurarsi che questo nuovo manifest js sia caricato modificando config / production.rb

config.assets.precompile += %w( admin.js )

Quindi regola il layout della pagina in modo da poter includere alcuni j extra per l'intestazione della pagina:

<%= content_for :header %>   

Quindi nelle viste in cui si desidera includere questo gruppo js specifico (così come il normale gruppo di applicazioni) e / o qualsiasi js, css ecc. Specifico per la pagina:

<% content_for :header do %>
  <%= javascript_include_tag 'admin' %>  
<% end %>

Ovviamente puoi fare la stessa cosa con css e raggrupparlo in modo simile per applicarlo solo a determinate aree del sito.


Se mantieni tutti i tuoi manifest nello stesso posto puoi dire alle rotaie di precompilare tutto in quella cartella. In questo modo devi solo modificare production.rb una volta e non tenere traccia di ciò che hai aggiunto.
Distruzione

Non sapevi che potevi farlo, quindi potresti avere una cartella 'manifest' che conteneva i tuoi manifest, così come i singoli gruppi js? Potrei provarlo. Vorrei che avessero una configurazione un po 'più sana di default in quanto sembra che supporranno semplicemente che glob tutto js in un unico grande file importato ovunque.
Kenny Grant,

strano, ottengo un errore Sprockets :: FileNotFound se uso //= require_tree ./global, ma non se utilizzo //= require_directory ./globalRails 3.2.12.
qix

2
Sembra che finirai con molti tag di script. Pensavo che l'obiettivo con la pipeline di risorse fosse avere un solo tag di script? Vorrei solo scrivere i javagram in modo che siano specifici della pagina.
Ziggy,

1
Penso di capire. Evitare tag di script aggiuntivi è piuttosto importante per il tempo di caricamento della pagina.
Ziggy

12

Queste risposte mi hanno aiutato moltissimo! Se qualcuno vuole un po 'di più ...

  1. È necessario inserire javascripts in manifest se si desidera che siano precompilati. Tuttavia, se hai bisogno di tutti i file javascript da application.js.coffeeallora, tutti i javacsripts verranno caricati ogni volta che navighi in una pagina diversa e lo scopo di fare javagram specifici della pagina verrà sconfitto.

Pertanto, è necessario creare il proprio file manifest (ad es. speciifc.js) Che richiederà tutti i file javascript specifici della pagina. Inoltre, modifica require_treedaapplication.js

app / attività / javascripts / application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global

app / attività / javascripts / specific.js

//= require_tree ./specific

Quindi, environments/production.rbaggiungi questo manifest all'elenco precompilato con l'opzione di configurazione,

config.assets.precompile += %w( specific.js )

Fatto! Tutti i javascripts condivisi che devono sempre essere caricati verranno inseriti nella app/assets/javascripts/globalcartella e in javascripts specifici della pagina app/assets/javascripts/specific. Puoi semplicemente chiamare i javagram specifici della pagina dalla vista come

<%= javascript_include_tag "specific/whatever.js" %> //.js è facoltativo.

Questo è sufficiente, ma volevo anche usarlo javascript_include_tag params[:controller]. Quando si creano controller, viene generato un file coffeescript associato app/assets/javascriptscome quelli menzionati da altre persone. Esistono davvero javascript specifici del controller , che vengono caricati solo quando l'utente raggiunge la vista del controller specifico.

Quindi ho creato un altro manifest controller-specific.js

app / attività / javascripts / Controller-specific.js

//= require_directory .

Ciò includerà tutti i coffeescript generati automaticamente associati ai controller. Inoltre, è necessario aggiungerlo all'elenco precompilato.

config.assets.precompile += %w( specific.js controller-specific.js )


Grazie mille per la risposta dettagliata. Dove dovrei mettere questa linea javascript_include_tag params[:controller]. Attualmente il mio application.html.erb ha questa linea javascript_include_tag 'application'. Dovrei sostituirlo con l'altra linea?
simha,

1
Inoltre, dovrei mettere questa linea <%= javascript_include_tag "specific/whatever.js" %>in un content_for :headerblocco?
simha,

1
È strano per me che tu debba fare casino config.assets.precompile. Tutto non è app/assets/javascripts/*.jsprecompilato automaticamente?
AlexChaffee,

@AlexChaffee Solo i file disponibili automaticamente sono application.csse application.js. Altri devono essere inclusi in altri file o elencati utilizzando config.assets.precompile. Leggi di più qui
Sung Cho,

La dichiarazione manifest è stata spostata. Sto correndo le rotaie 4.2.0. e ho trovato questo commento nel file production.rb: # config.assets.precompilee config.assets.versionsono passato a config / initializer / assets.rb
brusco

11

Preferisco il seguente ...

Nel tuo file application_helper.rb

def include_javascript (file)
    s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
    content_for(:head, raw(s))
end

e quindi nella tua vista particolare (app / views / books / index.html.erb in questo esempio)

<% include_javascript 'books/index.js' %>

... Sembra funzionare per me.


9

Se non vuoi usare la pipeline delle risorse o le complesse soluzioni per ottenere quel necessario javascript specifico per la pagina (simpatizzo), il modo più semplice e robusto, che ottiene lo stesso delle risposte sopra ma con meno codice è solo per uso:

<%= javascript_include_tag "my_javascipt_file" %>

Nota: ciò richiede una richiesta HTTP in più per tag include rispetto alle risposte che utilizzano content_for :head


javascript_include_tagera esattamente quello che stavo cercando, applausi AJP
Tom McKenzie il

dove metti "my_javascipt_file"? In attivi / javascript? Ma se è così, non verrebbe rilevato automaticamente con a //= require .in application.js?
qix

@Linus sì, //= require .porterebbe quello script in qualsiasi pagina del tuo sito, quindi dovresti fare qualcosa come Kenny Grant (uso //= require_tree ./global) o bjg suggerito.
AJP

1
Questo è stato di gran lunga il metodo più semplice per me, ho cambiato //= require_tree .a //= require_directory .in application.js e poi creato un sotto-directory in attività \ JavaScript. Nota che devi includere la nuova directory in config \ initializers \ assets.rb per precompilare il tuo js aggiungendo la riga:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy,


3

La mia comprensione è che la pipeline delle risorse ha lo scopo di ridurre il tempo di caricamento della pagina unendo tutti i tuoi js in un unico file (minimizzato). Mentre questo può sembrare ripugnante in superficie, in realtà è una caratteristica che esiste già in linguaggi popolari come C e Ruby. Cose come i tag "include" hanno lo scopo di prevenire l'inclusione multipla di un file e aiutare i programmatori a organizzare il loro codice. Quando si scrive e compila un programma in C, tutto quel codice è presente in ogni parte del programma in esecuzione, ma i metodi vengono caricati in memoria solo quando viene utilizzato quel codice. In un certo senso, un programma compilato non include nulla per garantire che il codice sia ben modulare. Rendiamo modulare il codice scrivendo i nostri programmi in quel modo e il sistema operativo carica solo nella memoria gli oggetti e i metodi di cui abbiamo bisogno per una determinata località. Esiste anche qualcosa di "inclusione specifica del metodo"? Se l'app Rails è riposante, questo è essenzialmente ciò che stai chiedendo.

Se scrivi il tuo javascript in modo che aumenti il ​​comportamento degli elementi HTML sulla pagina, quelle funzioni sono "specifiche della pagina" in base alla progettazione. Se c'è un codice complicato che hai scritto in modo tale da eseguirlo indipendentemente dal suo contesto, potresti considerare di legare comunque quel codice a un elemento html (potresti usare il tag body, come descritto nel metodo Garber-Irish ). Se una funzione viene eseguita in modo condizionale, le prestazioni saranno probabilmente inferiori rispetto a tutti quei tag di script aggiuntivi.

Sto pensando di usare la gemma paloma , come descritto nel progetto di app di rotaie . Quindi puoi rendere la tua pagina javascript specifica includendo le funzioni specifiche della pagina in un callback paloma:

Paloma.callbacks['users']['new'] = function(params){
    // This will only run after executing users/new action
    alert('Hello New Sexy User');
}; 

Usi le rotaie, quindi so che ami le gemme :)


3

Non dovresti caricare i tuoi file JS o CSS al di fuori della pipeline degli asset perché perdi funzioni importanti che rendono Rails così eccezionale. E non hai bisogno di un'altra gemma. Credo nell'utilizzare il minor numero possibile di gemme e non è necessario utilizzare una gemma qui.

Quello che vuoi è noto come "Javascript specifico del controller" ("Javascript specifico dell'azione è incluso nella parte inferiore). Ciò ti consente di caricare un file JavaScript specifico per un CONTROLLER specifico. Cercare di connettere il tuo Javascript a una vista è un po '.. indietro e non segue il modello di progettazione MVC. Si desidera associarlo ai controller o azioni all'interno dei controller.

Sfortunatamente, per qualsiasi motivo, gli sviluppatori di Rails hanno deciso che, per impostazione predefinita, ogni pagina caricherà ogni file JS situato nella directory delle risorse. Perché non abbiano mai deciso di farlo invece di abilitare "Javascript specifico del controller" per impostazione predefinita. Questo viene fatto tramite il file application.js, che include la seguente riga di codice per impostazione predefinita:

//= require_tree .

Questo è noto come direttiva . È ciò che utilizza i pignoni per caricare ogni file JS nella directory assets / javascripts. Per impostazione predefinita, i pignoni caricano automaticamente application.js e application.css e la direttiva require_tree carica tutti i file JS e Coffee nelle rispettive directory.

NOTA: quando impalcature (se non si tratta di impalcature, ora è un buon momento di iniziare), Rails genera automaticamente un file di caffè per te, per il controller di quell'impalcatura. Se vuoi che generi un file JS standard invece di un file di caffè , rimuovi la gemma di caffè abilitata di default nel tuo Gemfile e il tuo scaffold creerà invece file JS.

Ok, quindi il primo passo per abilitare "Javascript specifico del controller" è rimuovere il codice require_tree dal tuo file application.js, O cambiarlo in una cartella nella tua cartella assets / javascripts se hai ancora bisogno di file JS globali. IE:

//= require_tree ./global

Passaggio 2: accedi al tuo file config / initializer / assets.rb e aggiungi quanto segue:

%w( controllerone controllertwo controllerthree ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end

Inserisci i nomi dei controller che desideri.

Passaggio 3: Sostituisci javascript_include_tag nel tuo file application.html.erb con questo (nota la parte params [: controller]:

<%= javascript_include_tag 'application', params[:controller], 'data-turbolinks-track': 'reload' %>

Riavvia il tuo server e viola! Il file JS che è stato generato con il tuo scaffold ora verrà caricato solo quando viene chiamato quel controller.

Devi caricare un file JS specifico su una specifica AZIONE nel tuo controller , IE / articoli / nuovo ? Fallo invece:

application.html.erb :

<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>

config / initializer / assets.rb :

config.assets.precompile += %w(*/*)

Quindi aggiungi una nuova cartella con lo stesso nome del tuo controller nella cartella assets / javascripts e inserisci il tuo file js con lo stesso nome della tua azione. Lo caricherà quindi su quell'azione specifica.


1

Ok, forse questo è come il peggior lavoro di sempre, ma ho creato un metodo controller che ha appena reso il file .js

controllore

def get_script
   render :file => 'app/assessts/javascripts/' + params[:name] + '.js'
end
def get_page
   @script = '/' + params[:script_name] + '.js?body=1'
   render page
end

Visualizza

%script{:src => @script, :type => "text/javascript"}

se per qualche motivo non vogliamo farlo, fammelo sapere.


1

Il modo preferito per aggiungere JS è nel piè di pagina, quindi puoi farlo in questo modo:

show.html.erb:

<% content_for :footer_js do %>
   This content will show up in the footer section
<% end %>

layout / application.html.erb

<%= yield :footer_js %>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.