Используя Rails 3.1, где вы помещаете свой "JavaScript-код" javascript-кода?

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

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

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

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

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

Спасибо

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

Документы 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

Ответ 3

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

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

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-ready UTIL.init.

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

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

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

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

Ответ 4

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

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

//= require_tree .

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

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

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

Ключами являются:

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

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

Sujal

Ответ 5

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

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

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

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

Ответ 6

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

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

Смотрите: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline

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

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

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

<%= javascript_include_tag params[:controller] %>

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

Мой путь к атрибутам данных

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

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

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

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

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

  • Итерации по всем элементам в DOM, помеченным data-jstag
  • Для каждого элемента разделите значение атрибута на пробел, создав массив строк тегов.
  • Для каждой строки тега выполните поиск в Hash для этого тега.
  • Если найден подходящий ключ, запустите связанную с ним функцию, передав элемент в качестве параметра.

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

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

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

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

Ответ 7

На это были даны ответы и приняты давно, но я придумал свое решение на основе некоторых из этих ответов и моего опыта работы с 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 helper:

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

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

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

Ответ 8

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

<%= javascript_include_tag params[:controller] %>

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

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

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

Ответ 9

<%= javascript_include_tag params[:controller] %>

Ответ 10

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

Ответ 11

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

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

https://github.com/guidomb/loadjs

Ответ 12

Ответ Филиппа неплохой. Вот код, чтобы заставить его работать:

В application.html.erb:

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

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

<body class="projects">

Затем в projects.js.coffee:

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

Ответ 13

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

Ответ 14

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

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

Таким образом, я запускаю все страницы .css.sass с помощью

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

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

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

Надеюсь, это помогло кому-то.

Ответ 15

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

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

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

Ответ 16

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

Ответ 17

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

Примеры изменений

активы/JavaScripts/ application.js

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


просмотров/макеты/ application.html.erb

  ...
  </footer>

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

</body>
</html>


просмотров /Foo/ index.html.erb

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


активы /JavaScripts/ foo.js

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


активы /JavaScripts/foostuff/ foothis.js.coffee

alert "Hello world!"


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

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

  • Две строки, показанные выше в application.html.erb, указывают страницу, на которой должны быть указаны application.js и JS вашей страницы.

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

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

  • Храните свой собственный JS-код на странице, где вы можете легко ссылаться на него отдельно от другой пользовательской JS. В этом примере foo.js требует, чтобы дерево foostuff размещало ваш собственный JS, например foothis.js.coffee.

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

Примечания

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

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

Ответ 18

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

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

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

Ответ 19

Ответ на ryguy - хороший ответ, хотя он был опущен в отрицательные точки земли.

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

в show.html.erb, у вас будет что-то вроде:

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

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

<%= yield :javascript %>

Ответ 20

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

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

Ответ 21

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

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

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

$ ->
  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 есть несколько примеров этого, которые вы можете захотеть сокрушить, если вам интересно:)

Ответ 22

Paloma проект предлагает интересный подход для управления конкретным JavaScript-кодом страницы.

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

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

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

Ответ 23

Шаг1. Удалите require_tree. в ваших приложениях .js и application.css.

Step2. Измените файл application.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 %>

Step3. Добавить файл в 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/

Ответ 24

Я не пробовал это, но выглядит так:

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

  • Если вы хотите исключить файл из большого пакета javascript, вы должны войти в файл config/sprockets.yml и соответственно изменить исходные файлы. Затем вы просто включите любой из файлов, которые вы исключили там, где это необходимо.

Ответ 26

Я собрал несколько ответов на:

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

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

Макеты/application.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  

Ответ 27

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

application.js.coffee

$ ->
    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'")

users.js.coffee(конкретный диспетчерский кофейник, например, контроллер: пользователи, действие: панель инструментов)

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

application.html.haml

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

Ответ 28

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

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

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

Итак, теперь, где бы вы ни хотели, просто:

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

И что это, k?