Лучший способ добавить специфичный для страницы JavaScript в приложение Rails 3?

В Rails 3 есть немного ненавязчивый JavaScript, который довольно крутой.

Но мне было интересно, как лучше всего включить дополнительный JavaScript для конкретной страницы.

Например, где я мог бы сделать это ранее:

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

Теперь мы можем сделать это ненавязчивым с чем-то вроде

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

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

Итак, я думаю, мой вопрос, где / как включить этот JavaScript? Я не хочу заполнять application.js файл, потому что этот JavaScript применим только к этому одному представлению. Должен ли я как-то включить собственный файл JavaScript для каждой страницы или вставить его в переменную экземпляра, которую ищет заголовок?

10 ответов

Решение

Что мне нравится делать, так это включать Javascript для просмотра в content_for :head блок, а затем yield к этому блоку в макете вашего приложения. Например

Если он довольно короткий, то:

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

или, если дольше, то:

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

Затем в вашем файле макета

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

Если вы хотите включить javascript только на одной странице, вы, конечно, можете включить его на страницу, но если вы хотите сгруппировать свой javascript и использовать преимущества конвейера ресурсов, минимизированного js и т. Д., Это можно сделать и получить дополнительные Активы js, которые объединяются и загружаются только на определенных страницах, разбивая ваши js на группы, которые применяются только в определенных контроллерах / представлениях / разделах сайта.

Переместите ваши js-ресурсы в папки, с отдельным файлом манифеста для каждого, так что если у вас есть библиотека js-администратора, которая используется только в бэкэнде, вы можете сделать это:

  • активы
    • JavaScripts
      • админ
        • ... JS
      • admin.js (манифест для группы администраторов)
      • application.js (манифест для глобальной группы приложений)
      • Глобальный
        • ... JS

в существующем application.js

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

в новом файле манифеста admin.js

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

Убедитесь, что этот новый js-манифест загружен, отредактировав config / production.rb

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

Затем настройте макет страницы так, чтобы вы могли добавить несколько дополнительных js для заголовка страницы:

<%= content_for :header %>   

Затем в представлениях, где вы хотите включить эту конкретную группу js (а также обычную группу приложений) и / или любые специфичные для страницы js, css и т. Д.:

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

Конечно, вы можете сделать то же самое с css и сгруппировать его аналогичным образом для применения только к определенным областям сайта.

Эти ответы мне очень помогли! Если кто-то хочет немного больше...

  1. Вы должны поместить javascripts в манифесты, если вы хотите, чтобы они были предварительно скомпилированы. Тем не менее, если вам требуется каждый файл JavaScript из application.js.coffee тогда все javacsripts будут загружаться каждый раз, когда вы переходите на другую страницу, и цель создания специфичных для страницы javascript-скриптов будет побеждена.

Поэтому вам нужно создать свой собственный файл манифеста (например, speciifc.js), который потребует все специфичные для страницы файлы javascript. Кроме того, изменить require_tree от application.js

приложение / активы / JavaScripts / application.js

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

приложение / активы / JavaScripts / specific.js

//= require_tree ./specific

Тогда в вашем environments/production.rb добавить этот манифест в предварительно скомпилированный список с параметром config,

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

Готово! Все общие javascripts, которые всегда должны быть загружены, будут помещены в app/assets/javascripts/global папка, и специфичные для страницы javascripts в app/assets/javascripts/specific, Вы можете просто вызвать специфичные для страницы javascripts из вида как

<%= javascript_include_tag "specific/whatever.js" %> //.js не является обязательным.

Этого достаточно, но я хотел использовать javascript_include_tag params[:controller] тоже. Когда вы создаете контроллеры, соответствующий файл coffeescript генерируется в app/assets/javascripts как и другие упомянутые люди. Существуют действительно специфичные для контроллера javascripts, которые загружаются только тогда, когда пользователь достигает определенного вида контроллера.

Итак, я создал еще один манифест controller-specific.js

приложение / активы / JavaScripts / контроллер-specific.js

//= require_directory .

Это будет включать в себя все автоматически сгенерированные сценарии, связанные с контроллерами. Также вам нужно добавить его в предварительно скомпилированный список.

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

Я предпочитаю следующее...

В вашем файле application_helper.rb

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

а затем в вашем конкретном представлении (app/views/books/index.html.erb в этом примере)

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

... кажется, работает на меня.

Если вы не хотите использовать конвейер ресурсов или сложные обходные пути, чтобы получить необходимый javascript для конкретной страницы (я сочувствую), самый простой и надежный способ, который достигается так же, как и ответы выше, но с меньшим количеством кода, это просто использовать:

<%= javascript_include_tag "my_javascipt_file" %>

Примечание: для этого требуется еще один запрос http на каждый тег включения, чем ответы, которые используют content_for :head

Взгляните на драгоценный камень pluggable_js. Вы можете найти это решение проще в использовании.

Насколько я понимаю, конвейер ресурсов предназначен для уменьшения времени загрузки страницы путем объединения всех ваших js в один (минимизированный) файл. Хотя на первый взгляд это может показаться отвратительным, на самом деле это функция, которая уже существует в популярных языках, таких как C и Ruby. Такие вещи, как теги include, предназначены для предотвращения многократного включения файла и для помощи программистам в организации их кода. Когда вы пишете и компилируете программу на C, весь этот код присутствует в каждой части вашей работающей программы, но методы загружаются в память только тогда, когда этот код используется. В некотором смысле, скомпилированная программа не содержит ничего, чтобы гарантировать, что код является красиво модульным. Мы делаем код модульным, написав наши программы таким образом, и операционная система загружает в память только те объекты и методы, которые нам нужны для данной местности. Есть ли даже такая вещь, как "метод-специфическое включение"? Если ваше приложение rails спокойное, это, по сути, то, о чем вы просите.

Если вы пишете свой javascript так, чтобы он улучшал поведение HTML-элементов на странице, то эти функции являются "специфичными для страницы" по своему дизайну. Если есть какой-то сложный код, который вы написали таким образом, что он будет выполняться независимо от его контекста, возможно, стоит рассмотреть возможность привязки этого кода к элементу html (вы можете использовать тег body, как описано в методе Garber-Irish). Если функция выполняется условно, производительность, вероятно, будет меньше, чем у всех этих дополнительных тегов сценария.

Я думаю об использовании драгоценного камня paloma, как описано в проекте rails apps. Затем вы можете сделать свой javascript специфичным для страницы, включив специфичные для страницы функции в обратный вызов paloma:

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

Вы используете рельсы, так что я знаю, что вы любите драгоценные камни:)

Вы не должны загружать свои файлы JS или CSS за пределы конвейера ресурсов, потому что теряете важные функции, которые делают Rails таким замечательным. И тебе не нужен еще один драгоценный камень. Я верю в использование как можно меньшего количества драгоценных камней, и использование драгоценного камня здесь не обязательно.

То, что вы хотите, известно как "Javascript для конкретного контроллера" ("Javascript для конкретного действия включен внизу). Это позволяет вам загружать определенный файл JavaScript для определенного КОНТРОЛЛЕРА. Попытка подключить ваш Javascript к представлению является своего рода... назад и не следует шаблону проектирования MVC. Вы хотите связать его с вашими контроллерами или действиями внутри ваших контроллеров.

К сожалению, по какой-то причине разработчики Rails решили, что по умолчанию каждая страница будет загружать каждый файл JS, находящийся в вашем каталоге ресурсов. Почему они решили сделать это вместо включения "Javascript для контроллера" по умолчанию, я никогда не узнаю. Это делается с помощью файла application.js, который по умолчанию содержит следующую строку кода:

//= require_tree .

Это известно как директива. Это то, что sprockets использует для загрузки каждого файла JS в каталоге assets/javascripts. По умолчанию sprockets автоматически загружает application.js и application.css, а директива require_tree загружает каждый файл JS и Coffee в соответствующие каталоги.

ПРИМЕЧАНИЕ: Когда вы создаете скаффолд (если вы не скаффолдинг, сейчас самое время начать), Rails автоматически генерирует файл кофе для вас, для контроллера этого скаффолда. Если вы хотите, чтобы он генерировал стандартный файл JS вместо файла кофе, то удалите самоцвет кофе, включенный по умолчанию в вашем Gemfile, и ваш скаффолд будет создавать файлы JS.

Итак, первый шаг к включению "Javascript для конкретного контроллера" - это удалить код require_tree из вашего файла application.js, ИЛИ изменить его на папку в вашем каталоге assets/javascripts, если вам все еще нужны глобальные файлы JS. IE:

//= require_tree ./global

Шаг 2: Перейдите в файл config/initializers/assets.rb и добавьте следующее:

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

Вставьте нужные имена контроллеров.

Шаг 3: Замените javascript_include_tag в вашем файле application.html.erb следующим образом (обратите внимание на часть params[:controller]:

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

Перезагрузите свой сервер и альт! Файл JS, сгенерированный вашим скаффолдом, теперь будет загружаться только при вызове этого контроллера.

Нужно загрузить определенный файл JS на конкретный ДЕЙСТВИЕ в вашем контроллере, IE /article / new? Сделайте это вместо этого:

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(*/*)

Затем добавьте новую папку с тем же именем, что и у вашего контроллера, в папку assets/javascripts и поместите в нее свой js-файл с тем же именем, что и у вашего действия. Затем он загрузит его на это конкретное действие.

Предпочтительным способом добавления JS является нижний колонтитул, поэтому вы можете сделать это следующим образом:

show.html.erb:

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

макеты /application.html.erb

<%= yield :footer_js %>

Хорошо, так что, возможно, это как худшая работа, но я создал метод контроллера, который только что вывел файл.js

контроллер

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

Посмотреть

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

если по какой-то причине мы не хотим этого делать, дайте мне знать.

Другие вопросы по тегам