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

В 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 ]

150 голосов
/ 09 августа 2010

Мне нравится включать 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>
102 голосов
/ 15 августа 2012

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

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

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

в существующем приложении. 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 и сгруппировать его аналогичным образом для применения только к определенным областям сайта.

12 голосов
/ 17 мая 2011

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

В вашем файле 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' %>

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

11 голосов
/ 12 июня 2013

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

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

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

app / assets / javascripts / application.js

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

app / assets / javascripts / specific.js

//= require_tree ./specific

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

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

Готово!Все javascript-коды shared , которые должны всегда загружаться, будут помещены в папку app/assets/javascripts/global, а javascript-сценарии, специфичные для страницы, - в 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

app / assets / javascripts / controller-specific.js

//= require_directory .

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

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

9 голосов
/ 06 марта 2012

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

<%= javascript_include_tag "my_javascipt_file" %>

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

7 голосов
/ 25 июля 2013

Взгляните на pluggable_js gem. Возможно, вам будет проще использовать это решение.

3 голосов
/ 16 июня 2017

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

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

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

//= require_tree .

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

ПРИМЕЧАНИЕ: Когда вы строите леса (если вы не 't scaffolding, сейчас хорошее время для начала), Rails автоматически генерирует файл coffee для вас, для контроллера этого скаффолда.Если вы хотите, чтобы он генерировал стандартный файл JS вместо coffee , то удалите coffee gem , который по умолчанию включен в вашем 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] part:

<%= 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 с тем же именем, что и ваше действие, внутри.Затем он загрузит его на это конкретное действие.

3 голосов
/ 30 марта 2013

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

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

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

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

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

1 голос
/ 22 сентября 2014

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

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 %>
1 голос
/ 16 ноября 2012

Хорошо, возможно, это похоже на худшую работу, но я создал метод контроллера, который только что обработал файл .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"}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...