Le meilleur moyen d'ajouter du JavaScript spécifique à une page dans une application Rails 3?

159

Rails 3 a du JavaScript discret, ce qui est plutôt cool.

Mais je me demandais quel était le meilleur moyen d'inclure du JavaScript supplémentaire pour une page particulière.

Par exemple, là où j'aurais pu faire précédemment:

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

Nous pouvons maintenant le rendre discret avec quelque chose comme

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

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

Donc, je suppose que ma question est où / comment inclure ce JavaScript? Je ne veux pas remplir le application.jsfichier car ce JavaScript n'est applicable qu'à cette vue. Dois-je inclure un fichier JavaScript personnalisé pour chaque page ou le coller dans une variable d'instance recherchée par l'en-tête?

Brian Armstrong
la source
Pour ceux qui veulent bien comprendre comment cela fonctionne et ce qui est le mieux, veuillez lire railsapps.github.io/rails-javascript-include-external.html . C'est de loin la meilleure documentation que j'ai vue sur ce sujet. C'est une excellente lecture non seulement pour Rails, mais aussi pour quiconque s'occupe de développement Web. C'est pourquoi il est préférable de faire les choses à la manière des rails. J'utiliserai sûrement Unholy Rails pour mes futures questions. SENSATIONNEL.
DutGRIFF
2
@KateGregory que l'un est plus récent.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

153

Ce que j'aime faire, c'est inclure le Javascript par vue dans un content_for :headbloc, puis yieldce bloc dans la mise en page de votre application. Par exemple

Si c'est assez court alors:

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

ou, si plus long, alors:

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

Ensuite, dans votre fichier de mise en page

<head>
  ...
  <%= yield :head %>
</head>
bjg
la source
40
Pourquoi ne pas utiliser le <%= javascript_include_tag "my_javascipt_file" %> ?
AJP
5
@AJP Je suppose que cela va à l'encontre de l'objectif du pipeline d'actifs
lulalala
2
@lulalala mais le code de la réponse ne le fait-il pas de toute façon, mais de manière plus désordonnée?
AJP
8
@AJP c'est plus compliqué, mais il a une requête http de moins à faire que votre réponse.
lulalala
103

Si vous souhaitez inclure du javascript sur une seule page, vous pouvez bien sûr l'inclure sur la page en ligne, mais si vous souhaitez regrouper votre javascript et profiter du pipeline d'actifs, des js minifiés, etc., il est possible de le faire et d'avoir plus js qui sont combinés et chargés uniquement sur des pages spécifiques en divisant vos js en groupes qui ne s'appliquent qu'à certains contrôleurs / vues / sections du site.

Déplacez vos js dans les actifs dans des dossiers, avec un fichier manifeste distinct pour chacun, donc si vous aviez une bibliothèque js admin qui n'est utilisée que sur le backend, vous pouvez faire ceci:

  • les atouts
    • javascripts
      • admin
        • ... js
      • admin.js (manifeste pour le groupe d'administration)
      • application.js (manifeste pour le groupe global d'applications)
      • global
        • ... js

dans le fichier application.js existant

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

dans un nouveau fichier manifeste admin.js

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

Assurez-vous que ce nouveau manifeste js est chargé en éditant config / production.rb

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

Ensuite, ajustez votre mise en page afin que vous puissiez inclure quelques js supplémentaires pour l'en-tête de page:

<%= content_for :header %>   

Ensuite, dans les vues où vous souhaitez inclure ce groupe js spécifique (ainsi que le groupe d'applications normal) et / ou tout js, css, etc. spécifique à la page:

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

Vous pouvez bien sûr faire la même chose avec css et le regrouper de la même manière pour ne s'appliquer qu'à certaines zones du site.

Kenny Grant
la source
Si vous conservez tous vos manifestes au même endroit, vous pouvez dire aux rails de précompiler tout ce qui se trouve dans ce dossier. De cette façon, vous ne devez éditer production.rb qu'une seule fois et ne pas garder une trace de ce que vous avez ajouté.
Undistraction
Vous ne saviez pas que vous pouviez le faire - vous pourriez donc avoir un dossier «manifestes» contenant vos manifestes, ainsi que les groupes js individuels? Je pourrais essayer ça. Je souhaite qu'ils aient une configuration légèrement plus saine par défaut, car il semble qu'ils supposent que vous allez simplement regrouper tous les js dans un gros fichier importé partout.
Kenny Grant
étrange, j'obtiens une erreur Sprockets :: FileNotFound si j'utilise //= require_tree ./global, mais pas si j'utilise //= require_directory ./globalavec Rails 3.2.12.
qix
2
Il semble que vous vous retrouverez avec de nombreuses balises de script. Je pensais que l'objectif du pipeline d'actifs était de n'avoir qu'une seule balise de script? J'écrirais simplement les javascripts pour qu'ils soient spécifiques à la page.
Ziggy
1
Je pense que je comprends. Cependant, éviter les balises de script supplémentaires est assez important pour le temps de chargement de la page.
Ziggy
12

Ces réponses m'ont beaucoup aidé! Si quelqu'un veut un peu plus ...

  1. Vous devez mettre les javascripts dans les manifestes si vous voulez qu'ils soient précompilés. Cependant, si vous avez besoin de chaque fichier javascript à partir de application.js.coffeelà, tous les javacsripts seront chargés chaque fois que vous naviguez vers une page différente, et le but de faire des javascripts spécifiques à la page sera vaincu.

Par conséquent, vous devez créer votre propre fichier manifeste (par exemple speciifc.js) qui nécessitera tous les fichiers javascript spécifiques à la page. Modifiez également à require_treepartir deapplication.js

app / assets / javascripts / application.js

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

app / assets / javascripts / specific.js

//= require_tree ./specific

Ensuite, dans votre environments/production.rbajoutez ce manifeste à la liste précompilée avec l'option de configuration,

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

Terminé! Tous les javascripts partagés qui doivent toujours être chargés seront placés dans un app/assets/javascripts/globaldossier, et les javascripts spécifiques à la page dansapp/assets/javascripts/specific . Vous pouvez simplement appeler les javascripts spécifiques à la page à partir de la vue comme

<%= javascript_include_tag "specific/whatever.js" %> //.js est facultatif.

C'est suffisant, mais je voulais en faire un usage javascript_include_tag params[:controller]aussi. Lorsque vous créez des contrôleurs, un fichier coffeescript associé est généré app/assets/javascriptscomme les autres personnes mentionnées. Il existe des javascripts vraiment spécifiques au contrôleur , qui ne sont chargés que lorsque l'utilisateur atteint la vue spécifique du contrôleur.

Alors j'ai créé un autre manifeste controller-specific.js

app / assets / javascripts / controller-specific.js

//= require_directory .

Cela inclura tous les coffeescripts générés automatiquement associés aux contrôleurs. Vous devez également l'ajouter à la liste précompilée.

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

Maximus S
la source
Merci beaucoup pour la réponse détaillée. Où dois-je mettre cette ligne javascript_include_tag params[:controller]. Actuellement, mon application.html.erb a cette ligne javascript_include_tag 'application'. Dois-je le remplacer par l'autre ligne?
simha
1
Aussi, dois-je mettre cette ligne <%= javascript_include_tag "specific/whatever.js" %>dans un content_for :headerbloc?
simha
1
C'est étrange pour moi que vous ayez besoin de jouer avec config.assets.precompile. Tout n'est-il pas app/assets/javascripts/*.jsprécompilé automatiquement?
AlexChaffee
@AlexChaffee Seuls les fichiers disponibles automatiquement sont application.csset application.js. D'autres doivent être inclus dans d'autres fichiers ou répertoriés à l'aide de config.assets.precompile. Lire la suite ici
Sung Cho
La déclaration manifeste a été déplacée. Je cours des rails 4.2.0. et a trouvé ce commentaire dans le fichier production.rb: # config.assets.precompileet config.assets.versionont déménagé à config / initializers / assets.rb
laconique
11

Je préfère ce qui suit ...

Dans votre fichier application_helper.rb

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

puis dans votre vue particulière (app / views / books / index.html.erb dans cet exemple)

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

... semble fonctionner pour moi.

Cailinanne
la source
9

Si vous ne voulez pas utiliser le pipeline d'actifs ou les solutions de travail complexes pour obtenir le javascript spécifique à la page nécessaire (je sympathise), le moyen le plus simple et le plus robuste, qui permet d'obtenir les mêmes résultats que les réponses ci-dessus mais avec moins de code, consiste simplement à utilisation:

<%= javascript_include_tag "my_javascipt_file" %>

Remarque: cela nécessite une requête http de plus par balise include que les réponses qui utilisent content_for :head

AJP
la source
javascript_include_tagétait exactement ce que je cherchais, applaudit AJP
Tom McKenzie
où mettez-vous "my_javascipt_file"? Dans les actifs / javascripts? Mais si tel est le cas, cela ne serait-il pas repris automatiquement avec un //= require .dans l'application.js?
qix
@Linus ouais, //= require .apporterait ce script dans n'importe quelle page de votre site, vous devriez donc faire quelque chose comme Kenny Grant (utilisation //= require_tree ./global) ou bjg suggéré.
AJP
1
C'était de loin la méthode la plus simple pour moi, j'ai changé //= require_tree .pour //= require_directory .dans application.js puis j'ai créé un sous-répertoire dans assets \ javascripts. Notez que vous devez inclure le nouveau répertoire dans config \ initializers \ assets.rb pour précompiler vos js en ajoutant la ligne:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy
7

Jetez un œil à la gemme pluggable_js . Vous trouverez peut-être cette solution plus simple à utiliser.

peresleguine
la source
3

Je crois comprendre que le pipeline d'actifs est destiné à réduire le temps de chargement de la page en écrasant tous vos js ensemble dans un fichier (minifié). Bien que cela puisse sembler répugnant à première vue, il s'agit en fait d'une fonctionnalité qui existe déjà dans des langages populaires tels que C et Ruby. Des éléments tels que les balises "include" visent à empêcher l'inclusion multiple d'un fichier et à aider les programmeurs à organiser leur code. Lorsque vous écrivez et compilez un programme en C, tout ce code est présent dans chaque partie de votre programme en cours d'exécution, mais les méthodes ne sont chargées en mémoire que lorsque ce code est utilisé. Dans un sens, un programme compilé n'inclut rien pour garantir que le code est bien modulaire. Nous rendons le code modulaire en écrivant nos programmes de cette façon, et le système d'exploitation ne charge en mémoire que les objets et méthodes dont nous avons besoin pour une localité donnée. Existe-t-il même une «inclusion spécifique à la méthode»? Si votre application de rails est reposante, c'est essentiellement ce que vous demandez.

Si vous écrivez votre javascript de manière à augmenter le comportement des éléments HTML sur la page, ces fonctions sont de par leur conception «spécifiques à la page». S'il y a un code compliqué que vous avez écrit de manière à ce qu'il s'exécute quel que soit son contexte, envisagez peut-être de lier ce code à un élément html de toute façon (vous pouvez utiliser la balise body, comme décrit dans la méthode Garber-Irish ). Si une fonction s'exécute de manière conditionnelle, les performances seront probablement inférieures à toutes ces balises de script supplémentaires.

Je pense utiliser le joyau paloma , comme décrit dans le projet des applications rails . Ensuite, vous pouvez rendre votre page javascript spécifique en incluant des fonctions spécifiques à la page dans un callback paloma:

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

Vous utilisez des rails, donc je sais que vous aimez les gemmes :)

Ziggy
la source
3

Vous ne devriez pas charger vos fichiers JS ou CSS en dehors du pipeline d'actifs, car vous perdez des fonctionnalités importantes qui rendent Rails si génial. Et vous n'avez pas besoin d'un autre bijou. Je crois qu'il faut utiliser le moins de gemmes possible, et utiliser une gemme n'est pas nécessaire ici.

Ce que vous voulez est connu sous le nom de "Javascript spécifique au contrôleur" ("Javascript spécifique à l'action est inclus en bas). Cela vous permet de charger un fichier JavaScript spécifique pour un contrôleur spécifique. Essayer de connecter votre Javascript à une vue est en quelque sorte .. . à l'envers et ne suit pas le modèle de conception MVC. Vous souhaitez l'associer à vos contrôleurs ou à des actions dans vos contrôleurs.

Malheureusement, pour une raison quelconque, les développeurs de Rails ont décidé que par défaut, chaque page chargerait chaque fichier JS situé dans votre répertoire de ressources. Pourquoi ils ont décidé de faire cela au lieu d'activer "Controller Specific Javascript" par défaut, je ne le saurai jamais. Cela se fait via le fichier application.js, qui comprend la ligne de code suivante par défaut:

//= require_tree .

C'est ce qu'on appelle une directive . C'est ce que sprockets utilise pour charger chaque fichier JS dans le répertoire assets / javascripts. Par défaut, sprockets charge automatiquement application.js et application.css, et la directive require_tree charge chaque fichier JS et Coffee dans leurs répertoires respectifs.

REMARQUE: lorsque vous échafaudez (si vous n'êtes pas un échafaudage, c'est le bon moment pour commencer), Rails génère automatiquement un fichier café pour vous, pour le contrôleur de cet échafaudage. Si vous souhaitez qu'il génère un fichier JS standard au lieu d'un fichier café , supprimez la gemme de café activée par défaut dans votre Gemfile , et votre échafaudage créera des fichiers JS à la place.

Ok, donc la première étape pour activer "Controller Specific Javascript" est de supprimer le code require_tree de votre fichier application.js, OU de le changer dans un dossier dans votre répertoire assets / javascripts si vous avez encore besoin de fichiers JS globaux. C'EST À DIRE:

//= require_tree ./global

Étape 2: Accédez à votre fichier config / initializers / assets.rb et ajoutez ce qui suit:

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

Insérez les noms de contrôleurs souhaités.

Étape 3: Remplacez le javascript_include_tag dans votre fichier application.html.erb par ceci (notez la partie params [: controller]:

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

Redémarrez votre serveur et alto! Le fichier JS qui a été généré avec votre échafaudage ne se chargera désormais que lorsque ce contrôleur sera appelé.

Besoin de charger un fichier JS spécifique sur une ACTION spécifique dans votre contrôleur , IE / articles / new ? Faites ceci à la place:

application.html.erb :

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

config / initializers / assets.rb :

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

Ensuite, ajoutez un nouveau dossier avec le même nom que votre contrôleur dans votre dossier assets / javascripts et placez votre fichier js avec le même nom que votre action à l'intérieur. Il le chargera ensuite sur cette action spécifique.

Erick Maynard
la source
1

Ok alors peut-être que c'est comme le pire travail qui soit, mais je crée une méthode de contrôleur qui vient de rendre le fichier .js

Manette

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

Vue

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

si pour une raison quelconque nous ne voulons pas faire cela, faites-le moi savoir.

Facture
la source
1

La méthode préférée pour ajouter JS est dans le pied de page, vous pouvez donc le faire de cette façon:

show.html.erb:

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

layouts / application.html.erb

<%= yield :footer_js %>
Syed
la source