Використовуючи Rails 3.1, куди ви ставите свій «JavaScript-код»?


388

Наскільки я розумію, весь ваш JavaScript об'єднується в 1 файл. Rails робить це за замовчуванням, коли додає //= require_tree .внизу application.jsфайлу маніфесту.

Це здається справжнім рятувальником життя, але мене трохи непокоїть код JavaScript. Чи виконується цей код на кожній сторінці? Останнє, що я хочу, - це те, щоб усі мої об’єкти були примірниками для кожної сторінки, коли вони потрібні лише на 1 сторінці.

Крім того, чи немає потенціалу для коду, який також стикається?

Або ви ставите невеликий scriptтег внизу сторінки, який просто викликає метод, який виконує код javascript для сторінки?

Тоді вам більше не потрібен requ.js?

Дякую

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

Найкраще рішення, яке я можу придумати, - це загортати певні функції в divтеги з ids або classes. У коді JavaScript ви просто перевіряєте, idчи classє на сторінці або, і якщо він є, ви запускаєте код JavaScript, який з ним пов'язаний. Таким чином, якщо динамічний елемент відсутній на сторінці, код JavaScript не запускається, навіть незважаючи на те, що він включений у масивний application.jsфайл, упакований зірочками.

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

Я думаю, що це фактична відповідь на моє запитання.


11
"Шлях у напрямку Rails 3.1 - це загортати весь ваш Javascript у 1 файл, а не завантажувати окремий Javascript у нижній частині кожної сторінки." керувати JavaScript. Невеликі файли, як правило, краще (дивіться мої коментарі в інших місцях). Що стосується JavaScript, шлях Rails рідко є правильним шляхом (за винятком конвеєра активів, який наганяє дупу, та заохочення CoffeeScript).
Marnen Laibow-Koser

Отже, ви будете включати свої js-файли для кожної сторінки? Я думаю, що це марно, я більше погоджуюся з відповіддю ClosureCowboy.
герк

1
Ви подивилися на прийняту відповідь на це запитання? stackoverflow.com/questions/6571753 / ...
rassom

1
@DutGRIFF Іншими словами: ні, не найкраще в цьому випадку робити речі Rails (або, принаймні, не вводити все application.js), і насправді надана вами посилання вказує, чому це так: завантаження - це найповільніша частина процесу виконання JS. Багато маленьких файлів є більш кешованими, ніж один великий. Тоді, здається, люди, що не мають сумнівів, не усвідомлюють, що їх рекомендації не відповідають принципам, яких вони намагаються дотримуватися, і тому їхні рекомендації не слід сприймати серйозно.
Marnen Laibow-Koser

1
@DutGRIFF Ні, великий файл JS, як правило, не є гарною річчю, навіть коли він кешований. Перегляньте мої коментарі в інших місцях на цій сторінці: невеликі файли можуть краще орієнтуватися на конкретні сторінки, і їх можна кешувати з кращою деталізацією. Я не бачу хороший випадок використання для одного великого файлу , якщо немає сторінок конкретного коду на всіх .
Marnen Laibow-Koser

Відповіді:


157

Документи Asset Pipeline пропонують, як зробити JS, що відповідає конкретному контролеру:

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

Посилання на: material_pipeline


50
Це найелегантніший спосіб зробити це. Але також вам потрібно буде видалити рядок // = requ_tree. від application.js.coffee
zsljulius

2
Я повністю згоден з цим методом. Інші методи здаються дуже незграбними і все ще закінчуються завантаженням гігантського файлу js. Проект, який працює над проектом, має майже 2 Мб файлів / плагінів JS і т.д.
Білл Гаррісон

2
Я досить новачок у Rails, але мені здається, що це має бути поведінка за замовчуванням.
Росс Гамбрік

12
Для управління специфікою дії це є у моєму макеті, оскільки не кожна дія для кожного контролера має специфічний JS. page_specific_js = "#{params[:controller]}_#{params[:action]}"і потім; javascript_include_tag page_specific_js if Rails.application.assets.find_asset page_specific_js
Сухімічі

2
Чи все-таки конкретизовані дії контролера все-таки мінімізуються? Чи додаються вони до одного js-файлу, який створюється зірочками, або ж це призводить до декількох запитів файлів активів?
Джейсон

77

Для js-сторінок, що стосуються сторінки, ви можете використовувати рішення Garber-Irish .

Тож ваша папка 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-об'єкта та для UTIL.init, готового до DOM.

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

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

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

Я сподіваюся, що це вам допоможе.


4
Що робити, якщо вам потрібна змінна, доступна для всіх дій у контролері користувачів, але недоступна в інших контролерах? Чи не має у цього методу певних проблем щодо масштабування?
tybro0103

@ tybro0103, я думаю, щоб реалізувати цю поведінку, ви хотіли б написати щось на зразок window.varForOneController='val'у цій функції контролера init. Тут також може допомогти gon gem ( github.com/gazay/gon ). Можуть бути й інші вирішення.
welldan97

1
@ welldan97 Захист не для вашого пояснення - що чудово - а тому, що гарберсько-ірландська структура - зла. Він завантажує всі ваші JS на кожну сторінку і залежить від класів та ідентифікаторів елемента <body> для впорядкування речей. Це вірна ознака боротьби з DOM: за нормальних обставин елемент <body> не повинен мати клас або ідентифікатор, оскільки в документі існує лише один. Правильний спосіб зробити це - просто видалити JavaScript //= require_tree .і використовувати специфічний для сторінки JavaScript. Якщо ви активно намагаєтеся цього не робити, то прагнете до поганої практики.
Marnen Laibow-Koser

2
@ MarnenLaibow-Koser Особисто я вважаю, що завантаження всіх js на кожну сторінку добре для більшості проектів, коли ви об’єднуєте всі js в один файл і мінімізуєте його. Я вважаю, що в цілому користувач працює швидше. Принаймні, це більше схоже на конфлікт один js-файл проти багатьох (тобто дивіться на stackoverflow.com/questions/555696/… ). Також у використанні класів та ідентифікаторів на корпусі немає нічого поганого, якщо він спрощує код і працює для вас. Modernizr ( modernizr.com ) робить це, і деякі інші ліб теж.
welldan97

2
@ MarnenLaibow-Koser, трубопровід активів рейлів, мені здається, хороший кандидат для порівняння зі збіркою. Програміст записує свій JavaScript у приємні роз'єднані модулі, а потім він збирається разом, мінімізується та подається. Як і у випадку з компільованими мовами, завжди знайдуться програмісти, які вважають, що вони є на крок попереду компілятора ... але я думаю, що це рідко буває так.
Ziggy

65

Я бачу, що ви відповіли на власне запитання, але ось інший варіант:

В основному, ви робите припущення, що

//= 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


8
+1 Це чудово знати для новачка, як я. Я б дав +2, якби міг.
jrhorn424

5
@sujal Рівно. Основна команда Rails відома для бездоганного управління JavaScript. Не соромтесь ігнорувати їхні пропозиції та просто використовуйте хороші частини конвеєра активів. :)
Marnen Laibow-Koser

1
Дуже дякую за цю пораду. У мене немає декількох JS-файлів "найвищого рівня", залежно від модуля моєї програми. Добре працює.
elsurudo

1
+1 Важливим моментом тут для мене є те , що ви можете замінити //= require_tree .з , //= require_directory .так що ви можете зберегти всі існуючі файли , де вони і створювати нові каталоги для сторінки конкретних файлів.
zelanix

41

Інший варіант: щоб створити файли, орієнтовані на сторінку чи модель, ви можете створити каталоги всередині вашої assets/javascripts/папки.

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

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

Цю техніку можна використовувати і для style_sheets/.


13
Ти змусив мене зараз бажати кексів .. Dangit!
Чак Бергерон

Мені дуже подобається таке рішення. Єдина проблема, яка в мене виникає, полягає в тому, що ці додаткові маніфести не стискаються / не применшуються. Вони, однак, правильно складені. Є рішення чи я щось пропускаю?
clst

1
чи означає це, що браузер завантажує один js-файл, тобто комбінацію глобального + певного файлу сторінки?
lulalala

Не могли б ви поглянути на моє запитання, якщо у вас є? stackoverflow.com/questions/17055213/…
Maximus S

1
@clst Я вважаю, що це відповідь, яку ви шукаєте: guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
FrontierPsycho

23

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

Найкраще рішення, яке я можу придумати, - це загортати певні функції в divтеги з ids або classes. У коді javascript. Потім ви просто перевіряєте, idчи classє на сторінці або, і якщо він є, ви запускаєте код JavaScript, який з ним пов'язаний. Таким чином, якщо динамічний елемент відсутній на сторінці, код javascript не запускається, навіть незважаючи на те, що він включений до масивного application.jsфайлу, упакованого зірочками.

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

Я думаю, що це фактична відповідь на моє запитання.


Але ви дійсно бажаєте цих <script>тегів вручну . Так, класи та ідентифікатори є частиною відповіді, але користувачеві немає сенсу завантажувати JavaScript, який не вимагає саме ця сторінка.
Marnen Laibow-Koser

4
@ MarnenLaibow-Koser Причиною не додавання тегів сценарію вручну до кожної унікальної сторінки є те, що вам потрібно завантажувати цей вміст сценарію на кожному перегляді сторінки. Якщо ви можете впакувати весь javascript у application.js за допомогою конвеєра активів, користувач завантажує ці сценарії лише один раз і витягує application.js з кешу на всіх наступних завантаженнях сторінки
jakeonrails

@jakeonrails "Причина не додавання тегів сценаріїв вручну до кожної унікальної сторінки полягає в тому, що ви повинні завантажувати цей вміст сценарію на кожен перегляд сторінки" - абсолютно неправильно. Сценарій буде завантажено один раз, після чого буде отримано з кешу браузера за подальшими запитами. "Якщо ви можете запакувати весь javascript у application.js за допомогою конвеєра активів, то користувач завантажує ці сценарії лише один раз" —істи, але ціною безлічі зайвого коду. Якщо ви можете структурувати свій JS у багато маленьких файлів замість одного великого, ви отримаєте переваги кешування без зайвого коду.
Marnen Laibow-Koser

1
@ MarnenLaibow-Koser Я думаю, що було б краще сказати, що якщо ви упакуєте все в один сценарій, ваш користувач повинен завантажити лише 1 сценарій для будь-якої сторінки вашого сайту. Якщо у вас є кілька сценаріїв для різних частин програми, користувач, очевидно, повинен завантажити більше одного сценарію. Обидва способи будуть кешовані, звичайно, але в більшості випадків (додатки для малого та середнього рівня) обслуговування однієї application.js одноразово буде більш ефективною для завантаження. Розбір JS може бути іншою історією, залежно від того, що ви служите.
jakeonrails

1
@ Ziggy Крім того, якщо маленький файл використовується лише на 8 зі 100 сторінок, чому код повинен постійно знаходитися в кеші користувача? Краще насправді відкинути речі, які не потрібні.
Marnen Laibow-Koser

16

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

Шлях Rails 3.1 / 3.2 (Ні, сер. Мені це не подобається.)

Подивитися: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline

Я включаю наступне заради повноти у цій відповіді, і тому, що це не є життєздатним рішенням ... хоча я не дуже переймаюся цим.

"Шлях рейликів" - це рішення, орієнтоване на контролер, а не орієнтоване на перегляд, як запитував оригінальний автор цього питання. Існують спеціальні файли JS, названі на честь відповідних контролерів. Усі ці файли розміщуються в дереві папок, який НЕ включений за замовчуванням у жоден із застосунків директиви application.js.

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

<%= 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. Якщо знайдено відповідний ключ, запустіть пов'язану з ним функцію, передаючи елемент як параметр.

Тому скажіть, що я десь визначав десь у своєму 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 для конкретних сторінок, і це мені добре послужило як для простого дизайну сайтів, так і для більш складних / багатих додатків. Сподіваємось, одне з двох запропонованих нами тут рішень, мій шлях або шлях Рейки, є корисним для всіх, хто в майбутньому стикається з цим питанням.


6
Ще одна невелика деталь: у вашій відповіді є таке поняття, що щойно js буде кешований браузером, це не впливає. Це не зовсім так. Браузер дійсно не уникає завантаження, якщо файл js належним чином кешований, але він все ще компілює код на кожній сторінці візуалізації. Отже, ви повинні збалансувати компроміси. Якщо у вас багато JS у сукупності, але на одній сторінці використовується лише частина, ви, можливо, зможете покращити час сторінки, розбивши JS.
sujal

Докладніше про практичні ефекти цього кроку компіляції, про який я говорю, див. Пояснення 37 сигналів про те, як п’якс вплинув на Basecamp Наступний: 37signals.com/svn/posts/…
sujal

Це справедливий момент. Прочитавши статтю і оглянувшись на проекти, де я використав вищевказане рішення, я зрозумів, що написав по суті те саме рішення "надіслати змінений HTML", про яке вони згадують у статті. Часті перекомпіляції JS не були проблемою в моїх проектах через це. Крок компіляції - це те, про що я пам’ятаю, коли працюю на менш орієнтованих на настільних сайтах сайтах.
Райан

2
Відмовляючись від "Назвіть мене божевільним, але я хочу, щоб усі мої JS були зібрані та додані до application.js, коли я розгортаю" Ви дійсно не хочете цього, оскільки це змушує користувача завантажувати JavaScript, який він не потребує, і це змушує ваших обробників шукати атрибути, які навіть не збираються там. Мати все в app.js - це заманливо, і Rails, безумовно, полегшує, але належним чином - краще модулювати JavaScript.
Marnen Laibow-Koser

Ви маєте право на іншу думку ... і технічно маєте право на прихильність різниці думок. Однак було б непогано побачити певне обґрунтування того, чому один великий і кешований файл поступається, ніж примушує кілька запитів HTTP захоплювати модульований JS. Крім того, ви помиляєтесь щодо процедури пошуку обробника. Значення тегів НЕ шукаються. Здійснюється лише один пошук, який витягує всі елементи, які мають атрибут jstag data. Він не здійснює пошук за назвою тегів, він просто знаходить усі елементи, які мають теги, а потім інстанціює лише необхідні об’єкти.
Райан

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помічника:

<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!

Сподіваюсь, що допоможе хтось інший!


1
Це не спричинить проблеми після того, як активи будуть попередньо складені, а під час запуску <%= raw ... %>прибуток поверне 404?
Нішант

Я думаю, що конвеєр активів не дуже солодкий, оскільки він створює купу файлів, які часто не слід використовувати. Тож для мене, покладаючись на конвеєр активів, створює залежність від неефективної системи.
Дебора

1
@DeborahSpeece Коли конвеєр активів створює файли, які не слід використовувати? Ви плутаєте трубопровід активів (хороший) з require_tree /(поганий)?
Marnen Laibow-Koser

6

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

<%= javascript_include_tag params[:controller] %>

Ви також можете додати рядок для автоматичного завантаження файлу сценарію за принципом дії.

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

Просто помістіть сценарії сторінок у підкаталог, названий на ім'я контролера. У ці файли ви можете включити інші сценарії, використовуючи = requ. Було б непогано створити помічник для включення файлу лише за наявності, щоб уникнути помилки 404 у браузері.


6
<%= javascript_include_tag params[:controller] %>

2
Схоже, це може відповісти на запитання. Не могли б ви додати більше відповіді, щоб детальніше розібратися?


5

Індекс LoadJS - це ще один варіант:

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

https://github.com/guidomb/loadjs


3

Відповідь Філіпа досить хороша. Ось код, щоб змусити його працювати:

У application.html.erb:

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

Припустимо, що ваш контролер називається Projects, який генерує:

<body class="projects">

Потім у проектах.js.coffee:

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

Downvoting: будь-яке рішення , яке ставить клас на <body>це в силу самого факту невірно. Дивіться мої коментарі в інших місцях на цій сторінці.
Marnen Laibow-Koser

Не робіть цього. Проблема тут полягає в тому, що кожного разу, коли ви додаєте одне з них, ви додаєте ще один фрагмент js, який потрібно виконати при завантаженні сторінки. Однозначно може стати причиною погіршення продуктивності в міру зростання вашого проекту.
ifightcrime

2

JavaScripts об'єднуються лише тоді, коли ви скажете Rails (зірочки, швидше), щоб вони злилися.


Звичайно. Напевно, я запитую, тому що за замовчуванням Rails входить все в папку ... а це означає, що Девід має намір робити це. Але, як я вже говорив в іншому коментарі до @rubyprince, я не впевнений у виконанні, коли це робиться таким чином. Я думаю, що мені доведеться відключити //= require_tree .?
Вогнева емблема

@FireEmblem Так. require_tree .зазвичай погана ідея.
Marnen Laibow-Koser

2

Ось як я вирішив питання стилізації: (вибачте 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')

Сподіваюся, що це допомогло деяким.


1
Прочитайте ще раз останній біт. Для javascript ви можете скористатися тією ж структурою, що використовується для таблиць стилів для ініціалізації перегляду конкретних функцій.
zeeraw

Філіп, $('#post > #edit') ->здається, недійсним. Як ви надаєте можливості jQuery працювати в межах сфери?
Рамон Таяг

2
Нещодавно я почав завантажувати всі специфічні для контролера Java сценарії та таблиці стилів, викликаючи це у application.html.haml; = javascript_include_tag "application"і = javascript_include_tag params[:controller]таким чином я можу тримати код JavaScript обмеженим, не вказуючи область дії всередині файлу.
zeeraw


2

Я згоден з вашою відповіддю, щоб перевірити, чи є цей перемикач, використовуйте:

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

(не бачив, щоб хтось додав фактичне рішення)


2

Я не бачу відповіді, яка насправді поєднує все це та викладає для вас. Таким чином, я спробую скласти мелеял , суджал (a la ClosureCowboy ), першу частину відповіді Райана і навіть сміливе твердження Галя про Backbone.js ... все разом таким чином, що це коротко і зрозуміло. І, хто знає, я навіть можу відповідати вимогам Марнена Лайбоу-Козера .

Приклад редагувань

активи / javascripts / application.js

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


views / макети / 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>


views / 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" в область виходу 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.


це виглядає як шлях, я збираюся побачити, чи зможу я реалізувати це у власному додатку, дякую за детальну відповідь.
martincarlin87

1

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

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

Це все ще дозволяє завантажувати всі js рейками 3.x в одному невеликому пакеті, але не створює великих накладних витрат або конфліктів зі сторінками, для яких js не призначений.


1

Відповідь Ригу є хорошою відповіддю, навіть якщо вона була знищена в негативні моменти.

Особливо, якщо ви використовуєте щось на кшталт Backbone JS - для кожної сторінки є власний вигляд Backbone. Тоді у файлі erb є лише один рядок вбудованого javascript, який запускає правий клас перегляду магістральних даних. Я вважаю це єдиним рядком «клейового коду», а тому факт, що його вбудований текст є нормальним. Перевага полягає в тому, що ви можете зберегти ваше "Requ_tree", що дозволяє браузеру кешувати весь JavaScript.

у show.html.erb у вас з’явиться щось на кшталт:

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

і у вашому файлі компонування вам знадобляться:

<%= yield :javascript %>

Схильність Вбудований JavaScript ніколи не є хорошою ідеєю. Навіть якщо це клей-код, він повинен бути у зовнішньому файлі.
Marnen Laibow-Koser

1

Перемістіть усі JS-файли комунальних файлів у підпапку, наприклад "додаток / активи / JavaScript / глобальний", а потім у application.js, змініть //= require_tree .рядок на //= require_tree ./global.

Тепер ви можете розмістити JS для вашого контролера на корінці "app / elements / javascript /", і вони не будуть включені до складеного JS, а використовуються лише тоді, коли ви викликаєте їх через = javascript_include_tagваш контролер / view.


Ні в якому разі, це завантаження JavaScript для завантаження однієї сторінки. Навіть не важливо, чи це кешування.
jackyalcine

1

Хоча у вас є кілька відповідей тут, я думаю, що ваша редакція, мабуть, найкраща ставка. Шаблон дизайну, який ми використовуємо в нашій команді, який ми отримали від Gitlab, - це шаблон диспетчера. Він робить щось подібне до того, про що ви говорите, проте назва сторінки встановлюється в тезі тіла рельсами. Наприклад, у файл вашого макета просто включіть щось на зразок (у HAML):

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

Тоді 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 є кілька прикладів цього, з якими ви могли б повозитися, якщо вам цікаво :)


1

Проект " Палома " пропонує цікавий підхід до управління кодом JavaScript на конкретному веб-сайті.

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

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

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

1

Крок 1. видалити Requ_tree. у вашому application.js та application.css.

Крок2. Відредагуйте application.html.erb (за замовчуванням на рейках) у папці макета. Додайте "парами [: контролер]" у наступні теги.

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

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

Крок 3. Додайте файл у config / ініціалізатори / properties.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/


Хоча це теоретично може відповісти на питання, бажано було б сюди включити істотні частини відповіді та надати посилання для довідки.
Bhargav Rao

0

Я цього не пробував, але, схоже, це правда:

  • якщо у вас є content_for, що є javascript (наприклад, з реальним javascript всередині нього), зірочки не знали б про це, і, таким чином, це буде працювати так само, як і зараз.

  • якщо ви хочете виключити файл із великого пакета javascript, ви перейдете до файлу config / sprockets.yml і відповідно зміните файли source_files. Потім ви просто включите будь-який з файлів, які ви виключили, де потрібно.


Тоді "правильний шлях" виключення файлів або використання спеціального JavaScript на самій сторінці? Це так, як Давид задумав людей використовувати його?
Вогнева емблема

@FireEmblem Мені не дуже важливо, що Давид мав намір, тому що я не думаю, що Девід розуміє, як правильно організувати JavaScript.
Marnen Laibow-Koser


0

Я поєднав кілька відповідей у:

Допомога програми:

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  

0

По-перше: видаліть \\=require_treeз application.js Друге: весь ваш JS-код повинен бути розміщений у, /app/assets/javascritptа весь ваш CSS-код повинен бути розміщений у/app/assets/stylesheets


-2

Слідуючи керівництвом Райана, ось що я зробив-

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}}

Схильність Це смішно заплутано - не кажучи вже про небезпечні (через eval), якщо ваш HTML зірваний зламаним сервером або шкідливим сценарієм користувача.
Marnen Laibow-Koser

-3

Ось як це зробити, особливо якщо вам не доведеться виконувати тонни бібліотек для вашої конкретної сторінки, а лише запускати кілька сотень рядків JS більш-менш.

Оскільки цілком чудово вставляти Javascript-код у HTML, просто створіть у каталозі app / 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'

І це все, к?


2
Схильність Вбудований JavaScript ніколи не рекомендується. HTML повинен містити лише розмітку. JS і CSS повинні бути в окремих файлах, які можуть використовуватись повторно.
Marnen Laibow-Koser
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.