Используя Rails 3.1, где вы помещаете свой" специфичный для страницы " код JavaScript?


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

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

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

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

вам больше не нужно требовать.тогда Джей?

спасибо

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

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

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

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

29 381

29 ответов:

документы конвейера активов предлагают, как сделать JS для конкретного контроллера:

например, если a 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

для конкретной страницы js вы можете использовать Гарбер-ирландское решение.

таким образом, ваша папка 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, а на DOM-готовый UTIL.выполнение инициализации.

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

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

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

Я надеюсь, что это поможет вам.

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

в принципе, вы делаете предположение, что

//= require_tree .
это. Это не так. Не стесняйтесь, чтобы удалить его. В моем текущем приложении, первое, что я делаю с 3.1.X честно говоря, я сделал три разных файла 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

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

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

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

этот метод может быть использован для style_sheets/ как хорошо.

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

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

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

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

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

рельсы 3.1 / 3.2 путь (Нет, сэр. Мне это не нравится.)

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

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

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

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

<%= javascript_include_tag params[:controller] %>

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

Мой Атрибут Данных Путь

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

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

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

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

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

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

так сказать, у меня есть следующее определено где-то в моем приложении.js:

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", код автоматического предложения никогда не срабатывает. Тем не менее, он всегда есть, уменьшен и в конечном итоге кэшируется в моем приложении.js для тех случаев, когда мне это нужно на странице.

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

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

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

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

трубопровод активов сладкий. Использовать его.

во-первых, в своем , удалить //= 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!

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

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

<%= javascript_include_tag params[:controller] %>

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

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

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

<%= javascript_include_tag params[:controller] %>

может быть, вы найдете pluggable_js самоцвет как соответствующее решение.

The LoadJS gem-это еще один вариант:

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

https://github.com/guidomb/loadjs

ответ Филиппа довольно хорош. Вот код:

В приложения.формат html.Эрб:

<body class="<%=params[:controller].parameterize%>">

предполагая, что ваш контроллер называется проекты, которые будут генерировать:

<body class="projects">

затем в проектах.js.кофе:

jQuery ->
  if $('body.projects').length > 0  
     $('h1').click ->
       alert 'you clicked on an h1 in Projects'

JavaScripts объединяются только тогда, когда вы говорите Rails (скорее, звездочки), чтобы объединить их.

вот как я решил проблему стилизации: (извините расширения Haml)

%div{:id => "#{params[:controller].parameterize} #{params[:view]}"}
    = yield

таким образом, я начинаю все страницы конкретного .стиль CSS.Сасс файлы:

#post
  /* Controller specific code here */
  &#index
    /* View specific code here */
  &#new
  &#edit
  &#show

таким образом, вы можете легко избежать любого столкновения. Когда дело доходит до .js.кофе файлы, которые вы могли бы просто инициализировать элементы, такие как;

$('#post > #edit') ->
  $('form > h1').css('float', 'right')

надеюсь, что это помогло некоторым.

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

Я согласен с вашим ответом, чтобы проверить, есть ли этот селектор, используйте:

if ($(selector).length) {
    // Put the function that does not need to be executed every page
}

(не видел, чтобы кто-то добавил фактическое решение)

Я не вижу ответа, который действительно ставит все это вместе и выкладывает его для вас. Таким образом, я постараюсь поставить meleyal,sujal (а-ля ClosureCowboy), первая часть Райна ответ, и даже Гал смелое заявление о магистрали.js... все вместе в пути, который является коротким и ясным. И, кто знает, может быть, я даже встречу Marnen Laibow-Козери в требований.

пример правки

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

//= require jquery
//= require jquery_ujs
//= require lodash.underscore.min
...


просмотров/макеты/приложение.формат html.Эрб

  ...
  </footer>

  <!-- Javascripts ================================================== -->
  <!-- Placed at the end of the document so the pages load faster -->
  <%= javascript_include_tag "application" %>
  <%= yield :javascript %>

</body>
</html>


просмотров/foo/.формат html.Эрб

...
<% content_for :javascript do %>
  <%= javascript_include_tag params[:controller] %>
<% end %>


активы / javascripts/фу.js

//= require moment
//= require_tree ./foostuff


активы / javascripts/foostuff/ foothis.js.кофе

alert "Hello world!"


Краткая описание

  • удалить //= require_tree . С приложение.js и перечислите только JS, которые разделяет каждая страница.

  • две строки, показанные выше в приложение.формат html.Эрб укажите на странице, куда следует включить приложение.js и JS для вашей страницы.

  • три строки, показанные выше в .формат html.Эрб говорит вашему взгляду искать некоторые страницы конкретных JS и включить его в именованном область yield называется": javascript " (или как вы хотите ее назвать). В этом примере контроллер является "foo", поэтому Rails попытается включить " foo.js " в области :javascript yield в макете приложения.

  • список вашей страницы конкретных JS в фу.js (или как там называется контроллер). Перечислите общие библиотеки, дерево, каталоги, что угодно.

  • держите свои пользовательские страницы конкретных JS где-то, где вы можете легко ссылайтесь на него отдельно от других пользовательских JS. В этом примере, фу.js требует дерева foostuff, поэтому поместите туда свой пользовательский JS, например foothis.js.кофе.

  • здесь нет жестких правил. Не стесняйтесь перемещать вещи и, возможно, даже создавать несколько областей выхода с различными именами в различных макетах, если это необходимо. Это просто показывает один возможный первый шаг вперед. (Я не делаю это точно так, учитывая наше использование позвоночника.js. Я мог бы также выбрать чтобы бросить фу.js вниз в папку под названием foo вместо foostuff, но еще не решил этого.)

Примечания

вы можете делать подобные вещи с CSS и <%= stylesheet_link_tag params[:controller] %> но это выходит за рамки данного вопроса.

если я пропустил вопиющую лучшую практику здесь, пришлите мне записку, и я буду адаптироваться. Rails довольно новый для меня, и, честно говоря, я не очень впечатлен до сих пор хаосом, который он приносит по умолчанию для развития предпринимательства и всего трафик, который генерирует программа average Rails.

У меня есть другое решение, которое, хотя примитивно работает отлично для меня и не нуждается в каких-либо причудливых селективных стратегиях загрузки. Поместите в свой норнальный документ готовую функцию, но затем проверьте текущее местоположение windows, чтобы увидеть, является ли это страница, для которой предназначен ваш javascript:

$(document).ready(function() {
   if(window.location.pathname.indexOf('/yourpage') != -1) {
          // the javascript you want to execute
   }
}

Это по-прежнему позволяет загружать все js по рельсам 3.x в одном небольшом пакете, но не создает больших накладных расходов или каких-либо конфликтов со страницами, для которых js не предназначен.

ответ ryguy-хороший ответ, хотя он был понижен до отрицательных точек Земли.

особенно если вы используете что - то вроде Backbone JS-каждая страница имеет свой собственный вид Backbone. Тогда файл erb просто имеет одну строку встроенного javascript, который запускает правый класс представления магистрали. Я считаю, что это одна строка "кода клея" и, следовательно, тот факт, что его встроенный в порядке. Преимущество заключается в том, что вы можете сохранить свой "require_tree", который позволяет браузеру кэшировать все Яваскрипт.

в шоу.формат html.Эрб, у тебя будет что-то вроде:

<% provide :javascript do %>
  <%= javascript_include_tag do %>
    (new app.views.ProjectsView({el: 'body'})).render();
  <% end %>
<% end do %>

и в файле макета, вам понадобится:

<%= yield :javascript %>

переместите все ваши файлы commom JS в подпапку, такую как "app/assets/javascript/global", а затем в приложении.js, измените //= require_tree . строки //= require_tree ./global.

Теперь вы можете поместить свой контроллер-специфичный JS в корень " app/assets/javascript/", и они не будут включены в скомпилированный JS, используемый только тогда, когда вы вызываете их через = javascript_include_tag на ваш контроллер/вид.

хотя у вас есть несколько ответов здесь, я думаю, что ваше редактирование, вероятно, лучший выбор. Шаблон, который мы используем в нашей команде, что мы получили от Gitlab это шаблон диспетчером. Он делает что-то похожее на то, о чем вы говорите, однако имя страницы задается в теге body по rails. Например, в вашем файле макета просто включите что-то вроде (в HAML):

%body{'data-page' => "#{controller}:#{action}" }

тогда есть только одно закрытие и оператор switch в dispatcher.js.coffee файл в вашем папка javascripts выглядит так:

$ ->
  new Dispatcher()

class Dispatcher
  constructor: ->
    page = $('body').attr('data-page')
    switch page
      when 'products:index'
        new Products() 
      when 'users:login'
        new Login()

все, что вам нужно сделать в отдельных файлах (скажем products.js.coffee или login.js.coffee например) заключает их в класс, а затем глобализирует этот символ класса, чтобы вы могли получить к нему доступ в dispatcher:

class Products
  constructor: ->
    #do stuff
@Products = Products

у Gitlab есть несколько примеров этого, которые вы можете захотеть потыкать в случае, если вам интересно :)

Палома проект предлагает интересный подход к управлению конкретным javascript-кодом страницы.

пример использования из их документов:

var UsersController = Paloma.controller('Users');

// Executes when Rails User#new is executed.
UsersController.prototype.new = function(){
   alert('Hello Sexy User!' );
};

Шаг1. удалить require_tree . в вашем приложении.js и применение.стиль CSS.

Шаг2. Отредактируйте свое приложение.формат html.erb (по умолчанию rails) в папке макета. Добавьте "params [: controller]" в следующие теги.

<%= stylesheet_link_tag    'application', params[:controller], media: 'all', 'data-turbolinks-track' => true %>

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

Шаг3. Добавьте файл в config / initializers / assets.РБ

%w( controller_one controller_two controller_three ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.js.coffee", "#{controller}.css", "#{controller}.scss"]
end

ссылки: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/

Я не пробовал это, но, похоже, верно следующее:

  • Если у вас есть content_for, который является javascript (например, с реальным javascript в нем), звездочки не будут знать об этом, и поэтому это будет работать так же, как и сейчас.

  • Если вы хотите исключить файл из большого пакета javascript, вы перейдете в config/sprockets.YML-файл и соответствующим образом изменить source_files. Тогда, вы бы просто включить любой из файлов, которые вы исключили, где это необходимо.

Я сделал это ранее, используя этот метод: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/ . Супер-легко, полагается на контроллеры, чтобы выбрать правильный js для загрузки.

Я объединил некоторые ответы:

приложение Помощник:

module ApplicationHelper
  def js_page_specific_include
    page_specific_js = params[:controller] + '_' + params[:action]
    if Rails.application.assets.find_asset(page_specific_js).nil?
      javascript_include_tag 'application', 'data-turbolinks-track' => true
    else
      javascript_include_tag 'application', page_specific_js, 'data-turbolinks-track' => true
    end
  end
end

макеты/приложения.формат html.Haml на:

 <!DOCTYPE html>
%html{lang: 'uk'}
  %head   
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
   bla-bla-bla
    = js_page_specific_include   
   bla-bla-bla  

во-первых: удалить \=require_treeиз приложения.js Во-вторых: все ваши JS кода должна быть выделена в /app/assets/javascritpt и все ваши код CSS должна быть выделена в /app/assets/stylesheets

следуя примеру Райана, вот что я сделал -

приложение.js.кофе

$ ->
    view_method_name = $("body").data("view") + "_onload"
    eval("#{view_method_name}()") if eval("typeof #{view_method_name} == 'function'")
    view_action_method_name = $("body").data("view") + "_"+$("body").data("action")+"_onload"
    eval("#{view_action_method_name}()") if eval("typeof #{view_action_method_name} == 'function'")

пользователи.js.кофе (контроллер конкретного coffeescript, например контроллер: пользователи, действие: приборная панель)

window.users_dashboard_onload = () ->
    alert("controller action called")
window.users_onload = () ->
    alert("controller called")

приложение.формат html.Haml на

%body{:data=>{:view=>controller.controller_name, :action=>controller.action_name}}

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

Так как это прекрасно, чтобы встроить код Javascript в HTML, просто создать в разделе приложения/представления общих.каталог js и поместите туда свой код страницы/страниц внутри my_cool_partial.формат html.Эрб

<script type="text/javascript"> 
<!--
  var your_code_goes_here = 0;
  function etc() {
     ...
  }
-->
</script>

Так что теперь, откуда вы хотите, вы просто делаете:

  = render :partial => 'shared.js/my_cool_partial'

и и все, Кей?