Используя Rails 3.1, куда вы помещаете свой «специфичный для страницы» код JavaScript? - PullRequest
386 голосов
/ 29 мая 2011

Насколько я понимаю, все ваши JavaScript объединены в один файл.Rails делает это по умолчанию, когда добавляет //= require_tree . в конец файла манифеста application.js.

Это звучит как реальный спаситель жизни, но я немного обеспокоен специфичным для страницы кодом JavaScript.Этот код выполняется на каждой странице?Последнее, что я хочу, - чтобы все мои объекты создавались для каждой страницы, когда они нужны только на 1 странице.

Кроме того, нет ли возможности для кода, который тоже конфликтует?

Или вы помещаете маленький тег script внизу страницы, который просто вызывает метод, который выполняетjavascript код для страницы?

Вам больше не нужен require.js тогда?

Спасибо

РЕДАКТИРОВАТЬ : Я ценю все ответы ..и я не думаю, что они действительно решают проблему.Некоторые из них касаются стиля и, похоже, не связаны между собой ... а другие просто упоминают javascript_include_tag ... который, как я знаю, существует (очевидно ...), но может показаться, что путь к Rails 3.1 в будущем - обернутьобъедините весь ваш JavaScript в 1 файл, а не загружайте отдельный JavaScript в нижней части каждой страницы.

Лучшее решение, которое я могу придумать, - это обернуть определенные функции в теги div с id s илиclass ы.В коде JavaScript вы просто проверяете, присутствует ли на странице id или class, и, если это так, вы запускаете связанный с ним код JavaScript.Таким образом, если динамический элемент отсутствует на странице, код JavaScript не запускается - даже если он включен в массивный файл application.js, упакованный Sprockets.

Преимущество моего решения, приведенного выше, заключается в том, что еслиокно поиска включено на 8 из 100 страниц, оно будет работать только на этих 8 страницах.Вам также не нужно будет включать этот код на 8 страницах сайта.На самом деле, вам никогда больше не придется добавлять теги сценариев вручную на ваш сайт.

Я думаю, что это реальный ответ на мой вопрос.

Ответы [ 29 ]

157 голосов
/ 12 августа 2011

Документы Asset Pipeline предлагают, как сделать JS для конкретного контроллера:

Например, если генерируется ProjectsController, будет новый файл в app/assets/javascripts/projects.js.coffee, а другой в app/assets/stylesheets/projects.css.scss.Вы должны поместить любой JavaScript или CSS, уникальный для контроллера, в их соответствующие файлы ресурсов, поскольку эти файлы затем могут быть загружены только для этих контроллеров со строками, например <%= javascript_include_tag params[:controller] %> или <%= stylesheet_link_tag params[:controller] %>.

Ссылка на: asset_pipeline

77 голосов
/ 01 августа 2011

Для js для конкретной страницы вы можете использовать Garber-Irish Solution .

Таким образом, ваша папка Rails javascripts может выглядеть так для двух контроллеров - машин и пользователей:

javascripts/
├── application.js
├── init.js
├── markup_based_js_execution
├── cars
│   ├── init .js
│   ├── index.js
│   └── ...
└── users
    └── ...

И javascripts будет выглядеть так:

// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users

// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Your js code for all pages here
}

// cars/init.js

SITENAME.cars.init = function (){
  // Your js code for the cars controller here
}

// cars/index.js

SITENAME.cars.index = function (){
  // Your js code for the index method of the cars controller
}

и markup_based_js_execution будет содержать код для объекта UTIL и для выполнения UTIL.init, готового к DOM.

И не забудьте поместить это в файл макета:

<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">

Я также думаю, что лучше использовать классы вместо data-* атрибутов, для лучшей специфичной для страницы CSS. Как упоминал Джейсон Гарбер: CSS-селекторы для конкретной страницы могут быть очень неудобными (когда вы используете data-* атрибуты)

Надеюсь, это поможет вам.

65 голосов
/ 09 ноября 2011

Я вижу, что вы ответили на свой вопрос, но есть еще один вариант:

По сути, вы предполагаете, что требуется

//= require_tree .

.Это не.Не стесняйтесь удалить это.В моем текущем приложении, честно говоря, первое, что я делаю с 3.1.x, я сделал три разных JS-файла верхнего уровня.Мой application.js файл имеет только

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

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

Ключи:

  1. Вы можете удалить require_tree - Rails позволяет вам изменять допущения, которые он делает
  2. В имени application.js нет ничего особенного - любой файл в подкаталоге assets/javascript может содержать пред-процессорные директивы с //=

Надеюсь, что это поможет и добавит некоторые детали к ответу ClosureCowboy.

Sujal

40 голосов
/ 18 июня 2011

Другой вариант: для создания файлов, специфичных для страницы или модели, вы можете создать каталоги внутри папки assets/javascripts/.

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

Ваш основной файл манифеста application.js может быть настроен для загрузки его файлов из global/. Определенные страницы или группы страниц могут иметь свои собственные манифесты, которые загружают файлы из их собственных определенных каталогов. Звездочки автоматически объединят файлы, загруженные application.js, с файлами, специфичными для вашей страницы, что позволяет этому решению работать.

Эту технику можно использовать и для style_sheets/.

23 голосов
/ 30 мая 2011

Я ценю все ответы ... и я не думаю, что они действительно решают проблему.Некоторые из них касаются стиля и, похоже, не имеют отношения ... а другие просто упоминают javascript_include_tag ... который, как я знаю, существует (очевидно ...), но может показаться, что в будущем для Rails 3.1 нужно обернутьскопируйте весь свой Javascript в 1 файл, а не загружайте отдельный Javascript внизу каждой страницы.

Лучшее решение, которое я могу придумать, - это обернуть определенные функции в теги div с id s илиclass ы.В коде JavaScript.Затем вы просто проверяете, есть ли на странице id или class, и если это так, вы запускаете связанный с ним код javascript.Таким образом, если динамический элемент отсутствует на странице, код javascript не запускается - даже если он включен в массивный файл application.js, упакованный Sprockets.

Мое вышеописанное решение имеет то преимущество, что еслиокно поиска включено на 8 из 100 страниц, оно будет работать только на этих 8 страницах.Вам также не нужно будет включать этот код на 8 страницах сайта.На самом деле, вам никогда не придется добавлять теги сценариев вручную на ваш сайт когда-либо снова - за исключением, может быть, предварительной загрузки данных.

Я думаю, что это фактический ответ на мой вопрос.

16 голосов
/ 24 января 2012

Я понимаю, что приду на эту вечеринку немного поздно, но я хотел добавить решение, которое я использовал в последнее время. Тем не менее, позвольте мне сначала упомянуть ...

Rails 3.1 / 3.2 Way (Нет, сэр. Мне это не нравится.)

См .: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline

Для полноты изложения я включаю следующее и потому, что это не является нежизнеспособным решением ... хотя меня это не волнует.

"Rails Way" - это решение, ориентированное на контроллеры, а не ориентированное на просмотр, как просил первоначальный автор этого вопроса. Существуют специфичные для контроллера файлы JS, названные в честь соответствующих контроллеров. Все эти файлы помещаются в дерево папок, которое по умолчанию НЕ включено ни в один из приложений. Для директив jj требуются директивы.

Чтобы включить специфичный для контроллера код, в представление добавляется следующее.

<%= javascript_include_tag params[:controller] %>

Я ненавижу это решение, но оно есть и оно быстрое. Предположительно, вместо этого вы можете называть эти файлы чем-то вроде «people-index.js» и «people-show.js», а затем использовать что-то вроде "#{params[:controller]}-index", чтобы получить ориентированное на представление решение. Опять же, быстрое решение, но мне это не подходит.

Путь к атрибутам моих данных

Назовите меня сумасшедшим, но я хочу, чтобы ВСЕ мои JS компилировались и минимизировались в application.js при развертывании. Я не хочу помнить, чтобы повсюду включать эти маленькие файлы-бродяги.

Я загружаю все свои JS в один компактный файл, который скоро будет кэширован браузером. Если какой-то кусок моего application.js нужно запустить на странице, я позволяю HTML сообщать мне, а не Rails.

Вместо того, чтобы привязывать мой JS к определенным идентификаторам элементов или засорять мой HTML классами маркеров, я использую пользовательский атрибут данных с именем data-jstags.

<input name="search" data-jstag="auto-suggest hint" />

На каждой странице я использую - вставьте сюда предпочтительный метод библиотеки JS - для запуска кода после завершения загрузки DOM. Этот код начальной загрузки выполняет следующие действия:

  1. Перебирать все элементы в DOM, отмеченные data-jstag
  2. Для каждого элемента разделите значение атрибута на пробел, создав массив строк тегов.
  3. Для каждой строки тега выполните поиск в хэше для этого тега.
  4. Если найден соответствующий ключ, запустите связанную с ним функцию, передав элемент в качестве параметра.

Скажем, у меня в приложении определено следующее:

function my_autosuggest_init(element) {
  /* Add events to watch input and make suggestions... */
}

function my_hint_init(element) {
  /* Add events to show a hint on change/blur when blank... */
  /* Yes, I know HTML 5 can do this natively with attributes. */
}

var JSTags = {
  'auto-suggest': my_autosuggest_init,
  'hint': my_hint_init
};

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

Если какой-либо элемент не помечен data-jstag="auto-suggest", код автоматического предложения никогда не срабатывает. Тем не менее, он всегда присутствует, минимизируется и в конечном итоге кэшируется в моем application.js для тех случаев, когда он мне нужен на странице.

Если вам нужно передать дополнительные параметры вашим теговым функциям JS, вам придется применить некоторые творческие возможности. Либо добавьте атрибуты data-paramter, придумайте некоторый синтаксис параметров или даже используйте гибридный подход.

Даже если у меня есть какой-то сложный рабочий процесс, который кажется специфичным для контроллера, я просто создам для него файл в своей папке lib, запакую его в application.js и добавлю к нему что-то вроде 'new-thing-wizard'. Когда мой загрузчик попадет в этот тег, будет создан и запущен мой милый, причудливый волшебник. Он работает для представлений этого контроллера, когда это необходимо, но никак не связан с контроллером. На самом деле, если я правильно закодирую свой мастер, я смогу предоставить все данные конфигурации в представлениях и, следовательно, позже смогу повторно использовать мой мастер для любого другого контроллера, которому он нужен.

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

7 голосов
/ 16 октября 2012

На это уже давно был дан ответ, но я придумал собственное решение, основанное на некоторых из этих ответов и моем опыте работы с Rails 3+.

Конвейер активов сладок. Используйте это.

Сначала в вашем файле application.js удалите //= require_tree.

Затем в вашем application_controller.rb создайте вспомогательный метод:

helper_method :javascript_include_view_js //Or something similar

def javascript_include_view_js
    if FileTest.exists? "app/assets/javascripts/"+params[:controller]+"/"+params[:action]+".js.erb"
        return '<script src="/assets/'+params[:controller]+'/'+params[:action]+'.js.erb" type="text/javascript"></script>'
    end
end

Затем в файле макета application.html.erb добавьте нового помощника среди существующих включений javascript с префиксом помощника raw:

<head>
    <title>Your Application</title>
    <%= stylesheet_link_tag "application", :media => "all" %>
    <%= javascript_include_tag "application" %>
    <%= raw javascript_include_view_js %>
</head>

Вуаля, теперь вы можете легко создавать javascript для конкретного вида, используя ту же файловую структуру, что и везде в rails. Просто вставьте ваши файлы в app/assets/:namespace/:controller/action.js.erb!

Надеюсь, это поможет кому-то еще!

6 голосов
/ 21 марта 2013
<%= javascript_include_tag params[:controller] %>
6 голосов
/ 01 июля 2012

Вы можете добавить эту строку в свой файл макета (например, application.html.erb), чтобы автоматически загрузить специфичный для контроллера файл javascript (тот, который был создан при создании контроллера):

<%= javascript_include_tag params[:controller] %>

Вы также можете добавить строку для автоматической загрузки файла сценария для каждого действия.

<%= javascript_include_tag params[:controller] + "/" + params[:action] %>

Просто поместите скрипты вашей страницы в подкаталог, названный в честь имени контроллера. В эти файлы вы можете включить другие скрипты, используя = require. Было бы неплохо создать помощника для включения файла, только если он существует, чтобы избежать сбоя 404 в браузере.

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

Может быть, вы найдете pluggable_js gem в качестве подходящего решения.

...