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

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

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

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

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

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

спасибо

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

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

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

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

29 ответов


документы конвейера активов предлагают, как сделать 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


для конкретной страницы 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.исполнение init.

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

<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или classes. В коде 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 требует директив.

для включения кода, специфичного для контроллера, в вид.

<%= javascript_include_tag params[:controller] %>

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

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

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

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

вместо блокировки моего 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] %>

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


<%= javascript_include_tag params[:controller] %>

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


на 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.Сасс!--5--> файлы:

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

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

$('#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... все вместе, коротко и ясно. И, кто знает,может, я даже встречу ...--8-->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.кофе!--25-->

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.кофе!--25-->.

  • здесь нет жестких правил. Не стесняйтесь перемещать вещи и, возможно, даже создавать несколько областей выхода различных имен в различных макетах, если это необходимо. Это лишь показывает один возможный первый шаг вперед. (Я не делаю это именно так, учитывая наше использование позвоночника.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 по рельсам. Например, в вашем файле макета просто включите что-то вроде (в 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 например) заключает их в класс, а затем глобализирует этот символ класса, чтобы вы могли получить к нему доступ в диспетчере:

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.rb

%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 должен быть выделен в /app/assets/javascritpt и весь ваш код CSS должен быть выделен в /app/assets/stylesheets


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

приложение.js.кофе!--4-->

$ ->
    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, e.G контроллер: пользователи, действие: панель мониторинга)

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, просто создайте под app / views shared.каталог 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'

и это все, Кей?