Rails 3.1-Asset-Pipeline: Wie werden Controller-spezifische Skripte geladen?

76

Wenn ich in Rails 3.1 einen neuen Controller generiere, wird automatisch auch eine Javascript-Datei mit dem Namen des Controllers hinzugefügt. Erstens dachte ich, dass diese Javascript-Datei nur verwendet wird, wenn der zugehörige Controller aufgerufen wird.

Standardmäßig gibt es die Anweisung //= require_tree .in den application.js-Dateien, das jede JavaScript - Datei auf seinen Baum enthalten.

Wie kann ich nur das Controller-spezifische Skript laden?

Mike Bevz
quelle
3
Es ist vielleicht keine gute Idee, das zu tun. Bitte sehen Sie die Antworten auf diese verwandte Frage: stackoverflow.com/questions/8250951/…
gdelfino
1
Schreiben Sie Ihr Javascript so, dass es seitenspezifisch ist, und sorgen Sie sich dann nicht darum, dass alles zusammengefügt wird. Wenn dies kompilierter Code wäre, würden Sie das tun, richtig?
Ziggy
Spezifische Ansicht: stackoverflow.com/questions/6167805/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Antworten:

122

So laden Sie nur die erforderliche Datei name_of_the_js_file.js:

  1. entfernen Sie die //=require_treevonapplication.js

  2. Behalten Sie Ihre js-Datei (die Sie laden möchten, wenn eine bestimmte Seite geladen wird) in der Asset-Pipeline

  3. Fügen Sie einen Helfer hinzu application_helper.rb

    def javascript(*files)
      content_for(:head) { javascript_include_tag(*files) }
    end
    
  4. Geben Sie in Ihr Layout nach:

    <%= yield(:head) %>
    
  5. Fügen Sie dies in Ihre Ansichtsdatei ein:

    <% javascript 'name_of_the_js_file' %>
    

Dann sollte es ok sein

Nguyen Chien Cong
quelle
2
Es ist erwähnenswert, dass diese Methode in der Produktion gut funktioniert. Wenn Sie sich beispielsweise die Quelle in der Produktion ansehen, werden Sie feststellen, dass die Javascript-Datei des einzelnen Controllers genau wie die Hauptdatei application.js einen geeigneten Cache-Busting-Namen erhält: <script src = "/ assets / mycontroller-923cef714b82e7dec46117f9aab7fb2c.js" type = "text / javascript"> </ script>
cailinanne
Ja, da sich die Datei selbst in der Assets-Pipeline befindet. Wir wollen nur nicht, dass es in application.js benötigt wird.
Nguyen Chien Cong
1
Kannst du genauer sein? vielleicht kann ich helfen.
Nguyen Chien Cong
13
Stellen Sie sicher, dass Sie config/application.rbeine Zeile wie hinzufügen, da config.assets.precompile += %w(name_of_js_file.js)sonst Probleme wie bei der Vorkompilierung auftreten können. Siehe auch jalada.co.uk/2012/01/23/…
ZMorek
1
funktioniert für mich in Rails 3.2.3 (erfordert diese Option config.assets.precompile, wie von ZMorek oben angegeben)
Tatiana Tyu
83

Eine elegante Lösung hierfür besteht darin, controller_name in Ihrem Javascript_include_tag zu benötigen

Siehe http://apidock.com/rails/ActionController/Metal/controller_name/class

<%= javascript_include_tag "application", controller_name %>

controller_name.js wird geladen und befindet sich auch im Asset, sodass Sie von hier aus andere Dateien anfordern können.

Beispiel: Das Rendern von Autos # Index wird geben

<%= javascript_include_tag "application", "cars" %>

wo cars.js enthalten kann

//= require wheel
//= require tyre

Genießen !

albandiguer
quelle
Obwohl dies nach dem Lesen offensichtlich ist, fiel mir die Lösung nicht sofort ein.
Andrew Burns
11
Wenn Sie nicht für jede Datei eine Datei haben, treten controller_name.jsmöglicherweise einige Vorkompilierungsprobleme und Cache-Fehler auf, insbesondere wenn Sie nicht alle explizit vorkompilieren.
ZMorek
Vorkompilierungsprobleme werden durch die Einstellung config.assets.precompile behoben. Eine weitere Antwort auf diese Frage finden Sie im Kommentar von ZMorek.
Tatiana Tyu
1
Besser: <% = Javascript_include_tag Controller_Name, wenn Asset_Pfad (Controller_Name)%> <% = Stylesheet_Link_Tag Controller_Name, Medien: "Alle", wenn Asset_Pfad (Controller_Name)%>
Pencilcheck
1
@Pencilcheck Ihre Lösung funktioniert nicht. asset_pathgibt immer einen Pfad zurück, auch wenn die Datei nicht existiert
Alter Lagos
28

Ich füge dies immer in meine Layoutdateien ein. Es kann Ihr js zum Handeln bringen

<%= javascript_include_tag params[:controller] if AppName::Application.assets.find_asset("#{params[:controller]}.js") %>
<%= javascript_include_tag "#{params[:controller]}_#{params[:action]}"  if AppName::Application.assets.find_asset("#{params[:controller]}_#{params[:action]}.js") %>
Le Duc Duy
quelle
1
Obwohl ich das wirklich mag, scheint es in der Produktion nicht zu funktionieren.
Janosrusiczki
Die beste Lösung, nehme ich an.
Installero
3
@kitsched - Möglicherweise müssen Sie alle Ihre Assets zu config.assets.precompile über etwas wie stackoverflow.com/a/18992685/94668
TomFuertes
Danke, werde es versuchen.
Janosrusiczki
Dies ist die beste Lösung für mich. Und es funktioniert in der Produktion.
Jay
6

Ihr Problem kann auf verschiedene Arten gelöst werden.

Fügen Sie die Assets dynamisch hinzu

Bitte beachten Sie, dass dies keine gute Lösung für den Produktionsmodus ist, da Ihre Controller-Details nicht vorkompiliert werden!

  1. Fügen Sie unserem Anwendungshelfer die folgende Methode hinzu:

    module ApplicationHelper
        def include_related_asset(asset)
        #          v-----{Change this}
            if !YourApp::Application.assets.find_asset(asset).nil?
                case asset.split('.')[-1]
                    when 'js'
                        javascript_include_tag asset
                    when 'css'
                        stylesheet_link_tag asset
                end
            end
        end
    end
    
  2. Rufen Sie die layoutHilfsmethode in Ihrer Datei auf:

    <%= include_related_asset(params[:controller].to_param + '_' + params[:action].to_param . 'js') %>
    
  3. Erstellen Sie bestimmte Assets für Ihre Controller-Aktionen. Z.B.controller_action.js

Bitte vergessen Sie nicht YourApp, den Namen Ihrer App zu ändern .

Verwenden yield

  1. Fügen Sie <%= yield :head%>Ihrem Layoutkopf hinzu
  2. Fügen Sie Ihre Assets aus Ihren Aktionsansichten hinzu:

    <% content_for :head do %>
    <%= javascript_include_tag 'controller_action' %>
    <% end %>
    

Weitere Informationen finden Sie in den Rails-Handbüchern .

Robin
quelle
3

Ich mag die Lösung von Albandiguer . Womit ich festgestellt habe, dass Javascript / Coffeescript-Assets nicht einzeln vorkompiliert werden. Was bei der Verwendung allerlei Fehler verursacht javascript_path. Ich werde meine Lösung für dieses Problem mitteilen, nachdem ich ein Problem angesprochen habe, das einige Leute in seinen Kommentaren erwähnt haben. Hauptsächlich wird nur ein Teil des Controllers mit dem Namen JavaScript-Dateien behandelt.

Daher habe ich einen Anwendungshelfer erstellt, um festzustellen, ob die Datei unabhängig von der Erweiterung .coffee / .js im Javascript-Verzeichnis vorhanden ist:

module ApplicationHelper
  def javascript_asset_path(basename)
    Sprockets::Rails::Helper.assets.paths.select{|i|
      i =~ /javascript/ and i =~ /#{Rails.root}/
    }.each do |directory|
      if Dir.entries(directory).map {|i| i.split('.')[0]}.compact.
          include? basename
        return File.join(directory, basename)
      end
    end
    nil
  end
end

Diese Methode gibt den vollständigen Pfad zur Javascript-Datei zurück, falls vorhanden. Andernfalls wird null zurückgegeben. Nach dem Kommentar von Pencilcheck können Sie diese Methode für ein bedingtes Include hinzufügen:

<%= javascript_include_tag(controller_name) if javascript_asset_path(controller_name) %>

Und jetzt haben Sie eine richtige bedingte Aufnahme. Nun zur Ausgabe vorkompilierter Assets. Im Allgemeinen möchten Sie zur Optimierung keine Assets einzeln vorkompilieren . Sie können es jedoch tun, wenn Sie müssen:

# Live Compilation
config.assets.compile = true

Sie können dies in Ihrer Umgebungskonfigurationsdatei hinzufügen. Testen Sie es zuerst in Ihrer Entwicklungsumgebungsdatei. Auch dies ist nicht ratsam. Die Rails-Asset-Pipeline verwendet Sprockets, um alles zu optimieren:

Sprockets lädt die angegebenen Dateien, verarbeitet sie bei Bedarf, verkettet sie zu einer einzigen Datei und komprimiert sie dann (wenn Rails.application.config.assets.compress true ist). Durch das Bereitstellen einer Datei anstelle mehrerer Dateien kann die Ladezeit von Seiten erheblich reduziert werden, da der Browser weniger Anforderungen stellt. Durch die Komprimierung wird auch die Dateigröße reduziert, sodass der Browser sie schneller herunterladen kann.

BITTE LESEN Sie die Dokumentation, um weitere Einzelheiten zur Mechanik von Kettenrädern (Asset Pipeline) zu erfahren. Http://guides.rubyonrails.org/asset_pipeline.html

Assets werden nicht einzeln vorkompiliert. Zum Beispiel, wenn ich versuche:

<%= javascript_include_tag 'event' %>

Ich bekomme:

Pinion :: Rails :: Helper :: AssetFilteredError: Vermögensherausgefiltert und wird nicht bedient werden: add Rails.application.config.assets.precompile += %w( event.js )an config/initializers/assets.rbund starten Sie Ihren Server

So können Sie angeben, welche Assets einzeln vorkompiliert werden sollen. Wir müssen nur den entsprechenden Controller mit dem Namen Javascript-Dateien in unseren Asset-Initialisierer einfügen. Nun, wir können dies programmatisch tun.

Um eine Liste der Controllernamen zu erhalten, verwende ich das Beispiel von ecoologic :

all_controllers =  Dir[
    Rails.root.join('app/controllers/*_controller.rb')
  ].map { |path|
    path.match(/(\w+)_controller.rb/); $1
  }.compact

Um nun den Namen aller Javascript-Dateien zu erhalten, die mit dem Basisnamen des Controllernamens übereinstimmen, können Sie Folgendes verwenden:

javascripts_of_controllers = Sprockets::Rails::Helper.assets.paths.select{|a_path|
    a_path =~ /javascript/ and a_path =~ /#{Rails.root}/
  }.map {|a_path|
    Dir.entries(a_path)
  }.flatten.delete_if {|the_file|
    !the_file['.js']
  }.collect {|the_file|
    the_file if all_controllers.any? {|a_controller| the_file[a_controller]}
  }

Dann können Sie versuchen:

# config/initializers/assets.rb
Rails.application.config.assets.precompile += javascripts_of_controllers

Dadurch erhalten Sie eine Liste aller Javascript-Dateien ohne Verzeichnispfad, die Ihrem Controllernamen entsprechen. Beachten Sie, wenn Ihr Controller-Name Plural ist, sollte auch der Javascript-Name sein. Beachten Sie auch, dass wenn der Controller singulär ist und die Javascript-Datei Plural ist, diese weiterhin enthalten ist, da the_file[a_controller]eine teilweise Übereinstimmung erfolgreich ist.

Probieren Sie dies einfach in Ihrer Rails.application.config.assets.precompileUmgebung aus. Ich weiß, dass Sie dadurch die Liste der Dateien korrekt erhalten. Aber ich überlasse es Ihnen, es zu testen. Lassen Sie mich wissen, ob das Vorkompilieren auf diese Weise Nuancen mit sich bringt, da ich neugierig bin.

Eine sehr ausführliche Erklärung zur Vorkompilierung von Assets finden Sie in diesem Blog: http://www.sitepoint.com/asset-precompile-works-part/

6ft Dan
quelle
Wo soll ich all_controllers und javascripts_of_controllers Anweisungen ablegen?
Konstantin Voronov
1
Gut. Ich habe beide in meinen Assets-Initialisierer (Assets.rb) eingefügt, aber Sprockets :: Rails :: Helper.assets.paths war hier null, also musste ich es in Rails.application.config.assets.paths ändern, der Rest war in Ordnung. sehr schöne Lösung
Konstantin Voronov
1

Ich habe kürzlich einen einfachen Ansatz gefunden, um generierte Skripte für einen bestimmten Controller zu verwenden. Ich benutze für diese Lösung Edelstein Gon . Fügen Sie einen Controller hinzu:

class HomesController < ApplicationController
  before_filter :remember_controller

  private

  def remember_controller
    gon.controller = params[:controller]
  end
end

Öffnen Sie danach Ihre homes.js.cofeeund fügen Sie am Anfang der Datei hinzu:

jQuery ->
  if gon.controller == "sermons"
    # Place all functions here...

Das ist alles.

ExiRe
quelle