Найкращий спосіб додати певний сторінок JavaScript у додатку Rails 3?


159

У Rails 3 є ненав’язливий JavaScript, який досить класно.

Але мені було цікаво, який найкращий спосіб - включити додатковий JavaScript для певної сторінки.

Наприклад, де я, можливо, раніше:

<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>

Зараз ми можемо зробити це ненав'язливим з чимось подібним

<%= f.radio_button :rating, 'positive' %>

# then in some other file
$('user_rating_positive').click(function() {
  $('some_div').show();
}

Тож я думаю, моє запитання - де / як включити цей JavaScript? Я не хочу заповнювати application.jsфайл, оскільки цей JavaScript застосовується лише до цього одного представлення даних. Чи потрібно якось включати користувальницький файл JavaScript для кожної сторінки або вставляти його в змінну екземпляра, яку шукає заголовок?



Для тих, хто хоче повне розуміння того, як це працює і що найкраще, прочитайте railsapps.github.io/rails-javascript-include-external.html . Це далеко не найкраща документація, яку я бачив на цю тему. Це чудове читання не лише для Rails, але і для всіх, хто займається веб-розробниками. Ось чому найкраще робити речі поручні. Я точно буду використовувати Unholy Rails для моїх майбутніх питань. ОГО.
DutGRIFF

2
@KateGregory, що новіший.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


153

Що я люблю робити, це включити Javascript за перегляд у content_for :headблоці, а потім yieldдо цього блоку у макеті вашого додатка. Наприклад

Якщо він досить короткий, то:

<% content_for :head do %>
  <script type="text/javascript">
    $(function() {
      $('user_rating_positve').click(function() {
        $('some_div').show();
      }
    });
  </script>
<% end %>

або, якщо довше, то:

<% content_for :head do %>
  <script type="text/javascript">
    <%= render :partial => "my_view_javascript"
  </script>
<% end %>

Потім у вашому файлі компонування

<head>
  ...
  <%= yield :head %>
</head>

40
Чому б не використати <%= javascript_include_tag "my_javascipt_file" %> ?
AJP

5
@AJP Я здогадуюсь, це перемагає мету конвеєра активів
lulalala

2
@lulalala, але чи не в коді у відповіді це робити все-таки, але в стилі messier?
AJP

8
@AJP - це найгірше, але у нього є один менш http-запит, ніж ваша відповідь.
lulalala

4
Мені сподобалась ця стаття railsapps.github.com/rails-javascript-include-external.html
Ziggy

103

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

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

  • активи
    • javascripts
      • адмін
        • ... js
      • admin.js (маніфест для групи адміністратора)
      • application.js (маніфест для глобальної групи додатків)
      • глобальний
        • ... js

в існуючому application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder

у новому файлі маніфесту admin.js

//= require_tree ./admin // requires all js files in admin folder

Переконайтесь, що цей новий маніфест js завантажений редагуванням config / production.rb

config.assets.precompile += %w( admin.js )

Потім відрегулюйте макет сторінки, щоб ви могли включити додаткові js для заголовка сторінки:

<%= content_for :header %>   

Потім у представленнях, де ви хочете включити цю конкретну групу js (а також звичайну групу додатків) та / або будь-які js, css тощо для певної сторінки:

<% content_for :header do %>
  <%= javascript_include_tag 'admin' %>  
<% end %>

Звичайно, ви можете зробити те ж саме з css і згрупувати його аналогічним чином для застосування лише до певних ділянок сайту.


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

Ти не знав, що ти можеш це зробити - тож ти можеш мати папку «маніфести», яка містила ваші маніфести, а також окремі групи js? Я можу спробувати це. Я б хотів, щоб у них було дещо більш розумне налаштування за замовчуванням, оскільки, здається, вони припускають, що ви просто обведете всі js в один великий файл, імпортований скрізь.
Кенні Грант

непарно, я отримую зірочки :: FileNotFound помилка, якщо я використовую //= require_tree ./global, але не, якщо я використовую //= require_directory ./globalRails 3.2.12.
qix

2
Схоже, у вас з’явиться багато тегів сценарію. Я думав, що мета з конвеєром активів - мати лише один тег сценарію? Я б просто написав javascripts так, щоб вони були специфічними для сторінки.
Ziggy

1
Я думаю, я розумію. Уникаючи додаткових тегів сценарію, дуже важливо, щоб час завантаження сторінки.
Ziggy

12

Ці відповіді мені допомогли тонко! Якщо хтось хоче трохи більше ...

  1. Потрібно помістити javascripts у маніфести, якщо ви хочете, щоб вони були попередньо складені. Однак, якщо вам потрібен кожен файл javascript, application.js.coffeeтоді всі javacsripts завантажуватимуться кожного разу, коли ви переходите на іншу сторінку, і мета створення яваскриптів для певних сторінок буде розбита.

Тому вам потрібно створити свій власний файл маніфесту (наприклад speciifc.js), який потребуватиме всіх файлів javascript для певної сторінки. Також змінити require_treeзapplication.js

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

//= require jquery
//= require jquery_ujs
//= require_tree ./global

додаток / активи / javascripts / specific.js

//= require_tree ./specific

Потім у вашому environments/production.rbдодаванні цього маніфесту до попередньо складеного списку з параметром config,

config.assets.precompile += %w( specific.js )

Готово! Всі спільні javascripts, які завжди повинні бути завантажені, будуть розміщені в app/assets/javascripts/globalпапці, а специфічні для сторінки javascripts у app/assets/javascripts/specific. Ви можете просто зателефонувати на певні сторінки javascripts із вигляду, як

<%= javascript_include_tag "specific/whatever.js" %> //.js необов’язково.

Цього достатньо, але я теж хотів скористатися javascript_include_tag params[:controller]. Під час створення контролерів пов'язаний файл coffeescript створюється, app/assets/javascriptsяк і інші згадані люди. Є справді конкретні контролери javascripts, які завантажуються лише тоді, коли користувач досягне певного виду контролера.

Тому я створив ще один маніфест controller-specific.js

додаток / активи / javascripts / controller-specific.js

//= require_directory .

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

config.assets.precompile += %w( specific.js controller-specific.js )


Велике спасибі за детальну відповідь. Куди мені поставити цю лінію javascript_include_tag params[:controller]. Наразі мій application.html.erb має цей рядок javascript_include_tag 'application'. Чи слід замінити це іншим рядком?
simha

1
Крім того, я повинен поставити цю лінію <%= javascript_include_tag "specific/whatever.js" %>в content_for :headerблок?
simha

1
Мені дивно, що вам потрібно возитися config.assets.precompile. Чи все не app/assets/javascripts/*.jsпопередньо складено автоматично?
AlexChaffee

@AlexChaffee Тільки файли, доступні автоматично, є application.cssі application.js. Інші повинні бути або включені до інших файлів, або перелічені за допомогою config.assets.precompile. Детальніше читайте тут
Sung Cho

Декларація маніфесту переміщена. Я бігаю по рейках 4.2.0. і знайшов цей коментар у файлі production.rb: # config.assets.precompileі config.assets.versionперейшов до конфігурації / ініціалізаторів / tools.rb
curt

11

Я віддаю перевагу наступному ...

У вашому файлі application_helper.rb

def include_javascript (file)
    s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
    content_for(:head, raw(s))
end

а потім у вашому конкретному представленні (додаток / представлення / книги / index.html.erb у цьому прикладі)

<% include_javascript 'books/index.js' %>

... здається, працює на мене.


9

Якщо ви не хочете використовувати конвеєр активів або складну роботу оточуєте, щоб отримати необхідний JavaScript специфічний javascript (я співчуваю), найпростіший і надійний спосіб, який досягає того ж, що відповіді вище, але з меншим кодом - просто використання:

<%= javascript_include_tag "my_javascipt_file" %>

Примітка: для цього потрібен ще один http-запит на тег включення, ніж відповіді, які використовуються content_for :head


javascript_include_tagсаме те, що я шукав, ура AJP
Том Маккензі

куди ви ставите "my_javascipt_file"? В активах / javascripts? Але якщо так, чи не отримає це автоматично автоматично з a //= require .в application.js?
qix

@Linus yep, запустить //= require .цей скрипт на будь-яку сторінку на вашому сайті, тому вам доведеться зробити щось на кшталт запропонованого Кенні Гранта (використання //= require_tree ./global) або bjg.
AJP

1
Це був, безумовно, найпростіший метод для мене, я змінив //= require_tree .на //= require_directory .application.js, а потім створив підкаталог в активах \ javascripts. Зауважте, що вам потрібно включити новий каталог у config \ inicijalizers \ imov.rb, щоб попередньо компілювати ваш js, додавши рядок:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy


3

Я розумію, що конвеєр ресурсів має на увазі скоротити час завантаження сторінки шляхом перемішування всіх ваших js в один (мінімізований) файл. Хоча це може здатися огидним на поверхні, це насправді функція, яка вже існує в популярних мовах, таких як C і Ruby. Такі речі, як теги "включати", покликані запобігти багаторазовому включенню файлу та допомогти програмістам впорядкувати їх код. Коли ви пишете та компілюєте програму на C, весь цей код присутній у кожній частині вашої запущеної програми, але методи завантажуються в пам'ять лише тоді, коли цей код використовується. У певному сенсі складена програма не містить нічого, щоб гарантувати, що код є гарним модульним. Ми робимо код модульним, записуючи таким чином наші програми, і операційна система завантажує в пам'ять лише ті об'єкти та методи, які нам потрібні для даної місцевості. Чи існує навіть таке поняття, як "специфічне включення"? Якщо ваш рейковий додаток спокійний, це, по суті, те, про що ви просите.

Якщо ви пишете свій JavaScript так, щоб він доповнював поведінку HTML-елементів на сторінці, то ці функції за дизайном є "специфічними для сторінки". Якщо є якийсь складний код, який ви написали таким чином, що він буде виконуватися незалежно від його контексту, можливо, подумайте про прив'язку цього коду до елемента html (ви можете використовувати тег body, як описано в методі Гарбер-Ірландський ). Якщо функція виконується умовно, продуктивність буде, ймовірно, меншою, ніж усі ці додаткові теги сценарію.

Я маю в виду , використовуючи Paloma дорогоцінний камінь, як описано в додатків рейлів . Тоді ви можете зробити вашу сторінку JavaScript, включивши певні сторінки в зворотний виклик паломи:

Paloma.callbacks['users']['new'] = function(params){
    // This will only run after executing users/new action
    alert('Hello New Sexy User');
}; 

Ти використовуєш рейки, тож я знаю, ти любиш дорогоцінні камені :)


3

Ви не повинні завантажувати файли JS або CSS за межами конвеєра активів, оскільки ви втрачаєте важливі функції, які роблять Rails так великими. І вам не потрібен інший дорогоцінний камінь. Я вважаю, що можна використовувати якомога менше дорогоцінних каменів, і використовувати дорогоцінний камінь тут не потрібно.

Те, що ви хочете, відоме як "Javascript JavaScript" ("Внизу визначений конкретний Javascript). Це дозволяє завантажувати конкретний файл JavaScript для конкретного КОНТРОЛЕРУ. Спроба підключити Javascript до представлення виглядає .. назад і не відповідає схемі дизайну MVC. Ви хочете пов’язати його з контролерами або діями всередині ваших контролерів.

На жаль, з будь-якої причини Rails devs вирішив, що за замовчуванням на кожну сторінку завантажуватимуться всі файли JS, що знаходяться у вашому каталозі активів. Чому вони вирішили це зробити замість того, щоб увімкнути "Javascript JavaScript" за замовчуванням, я ніколи не дізнаюся. Це робиться через файл application.js, який включає типовий рядок коду за замовчуванням:

//= require_tree .

Це відомо як директива . Це те, що зірочки використовують для завантаження кожного JS-файлу в каталог активів / javascripts. За замовчуванням зірочки автоматично завантажують application.js та application.css, а директива Requ_tree завантажує всі файли JS та Coffee у відповідних каталогах.

ПРИМІТКА. Коли ви складаєте ліси (якщо ви не є будівельними лісами, зараз прийшов час для початку), Rails автоматично генерує файл для кави для вас для контролера цього лісу. Якщо ви хочете, щоб він генерував стандартний файл JS замість файлу кави , тоді видаліть кавовий камінь, який увімкнено за умовчанням у вашому Gemfile , і ваш ешафот створить натомість файли JS.

Гаразд, тому перший крок до включення "Javascript JavaScript" - це видалити код Requ_tree з файлу application.js, АБО змінити його в папку в каталозі активів / javascripts, якщо вам все ще потрібні глобальні файли JS. IE:

//= require_tree ./global

Крок 2: Перейдіть у свій файл config / inicijalizer / elements.rb і додайте наступне:

%w( controllerone controllertwo controllerthree ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end

Вставте потрібні імена контролера.

Крок 3: Замініть javascript_include_tag у вашому файлі application.html.erb цим (зверніть увагу на частину params [: controller]:

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

Перезавантажте сервер та альта! Файл JS, сформований із вашим ешафтом, тепер завантажується лише тоді, коли викликається цей контролер.

Потрібно завантажити певний файл JS для певної ДІЇ у контролер , IE / статті / new ? Зробіть це замість цього:

application.html.erb :

<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>

config / ініціалізатори / asset.rb :

config.assets.precompile += %w(*/*)

Потім додайте нову папку з тим самим іменем, що і контролер, у папку активів / javascripts і помістіть файл js з тим самим іменем, що і ваша дія. Потім він завантажить його на ту конкретну дію.


1

Добре, можливо, це як найгірша робота навколо коли-небудь, але я створив метод контролера, який щойно вивів файл .js

Контролер

def get_script
   render :file => 'app/assessts/javascripts/' + params[:name] + '.js'
end
def get_page
   @script = '/' + params[:script_name] + '.js?body=1'
   render page
end

Вид

%script{:src => @script, :type => "text/javascript"}

якщо ми чомусь не хочемо цього робити, то дайте мені знати.


1

Кращий спосіб додавання JS знаходиться у нижньому колонтитулі, тому ви можете зробити наступний спосіб:

show.html.erb:

<% content_for :footer_js do %>
   This content will show up in the footer section
<% end %>

макети / application.html.erb

<%= yield :footer_js %>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.