Конвеєр активів Rails 3.1: як завантажити сценарії для контролера?


76

Якщо я створюю новий контролер у Rails 3.1, автоматично додається також файл javascript із назвою контролера. По-перше, я думав, що цей файл javascript буде використовуватися лише тоді, коли буде викликаний відповідний контролер.

За замовчуванням //= require_tree .в application.js-file є інструкція , яка включає кожен файл javascript у цьому дереві.

Як я міг завантажити лише скрипт, який відповідає контролеру?


3
Можливо, це не гарна ідея робити це. Будь ласка , дивіться відповіді на цей суміжний питання: stackoverflow.com/questions/8250951 / ...
gdelfino

1
Напишіть свій javascript так, щоб він мав конкретну сторінку, і тоді не хвилюйтеся з приводу того, що все разом змішано. Якби це був скомпільований код, це те, що ви зробили б, так?
Ziggy

Відповіді:


122

Щоб завантажити лише необхідний файл name_of_the_js_file.js:

  1. видалити //=require_treeзapplication.js

  2. зберігайте свій файл js (який ви хочете завантажити, коли завантажується певна сторінка) у конвеєрі активів

  3. додати помічника в application_helper.rb

    def javascript(*files)
      content_for(:head) { javascript_include_tag(*files) }
    end
    
  4. поступка у вашому макеті:

    <%= yield(:head) %>
    
  5. додайте це у свій файл перегляду:

    <% javascript 'name_of_the_js_file' %>
    

Тоді це повинно бути нормально


2
Варто зазначити, що цей метод добре працює у виробництві. Наприклад, якщо ви подивитеся на виробниче джерело, ви побачите, що окремий файл javascript контролера отримує відповідне ім'я для знищення кешу, як і основний файл application.js: <script src = "/ assets / mycontroller-923cef714b82e7dec46117f9aab7fb2c.js" type = "text / javascript"> </script>
cailinanne

Так, оскільки сам файл знаходиться в конвеєрі активів. Ми просто не хочемо, щоб це вимагалося в application.js.
Nguyen Chien Cong,

1
Чи можете ви бути більш конкретними? можливо, я можу допомогти.
Nguyen Chien Cong

13
обов’язково додайте до свого config/application.rbрядка, як-от, config.assets.precompile += %w(name_of_js_file.js)або ви можете отримати попередньо скомпільовані проблеми, як це робив я. Див. Також jalada.co.uk/2012/01/23/…
ZMorek

1
працює для мене в рейках 3.2.3 (потрібна ця опція config.assets.precompile, як зазначено вище ZMorek)
Тетяна Тю

83

Елегантним рішенням для цього є вимагати ім’я_контролера у вашому тегу javascript_include_tag

див. http://apidock.com/rails/ActionController/Metal/controller_name/class

<%= javascript_include_tag "application", controller_name %>

controller_name.js буде завантажено і також знаходиться в активі, тому ви можете вимагати інші файли звідси.

Наприклад, візуалізація автомобілів # покаже індекс

<%= javascript_include_tag "application", "cars" %>

де cars.js може містити

//= require wheel
//= require tyre

Насолоджуйтесь!


Хоча це очевидно після його прочитання, рішення не одразу прийшло мені в голову.
Ендрю Бернс,

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

Проблеми з попередньою компіляцією вирішуються налаштуваннями config.assets.precompile - див. коментар ZMorek, щоб отримати іншу відповідь на це питання.
Тетяна Тю

1
Краще: <% = javascript_include_tag ім'я_контролера, якщо шлях_активу (ім'я_контролера)%> <% = таблиця_стилів_посилання_тегу ім'я_контролера, носій: "все", якщо шлях_активу (ім'я_контролера)%>
Перевірка олівцем

1
@Pencilcheck Ваше рішення не працює. asset_pathзавжди повертає шлях, навіть якщо файл не існує
Alter Lagos

28

Я завжди включаю це до своїх файлів макета. Він може застосувати ваш js до дії

<%= javascript_include_tag params[:controller] if AppName::Application.assets.find_asset("#{params[:controller]}.js") %>
<%= javascript_include_tag "#{params[:controller]}_#{params[:action]}"  if AppName::Application.assets.find_asset("#{params[:controller]}_#{params[:action]}.js") %>

1
Хоча мені це дуже подобається, схоже, це не працює на виробництві.
janosrusiczki

Я вважаю, найкраще рішення.
installero

3
@kitsched - можливо, вам доведеться додати всі свої активи до config.assets.precompile через щось на зразок stackoverflow.com/a/18992685/94668
TomFuertes

Дякую, спробую.
janosrusiczki

Це найкраще рішення для мене. І це працює на виробництві.
Джей,

6

Вашу проблему можна вирішити різними способами.

Додайте активи динамічно

Будь ласка, врахуйте, що це не є гарним рішенням для виробничого режиму, оскільки особливості вашого контролера не будуть попередньо скомпільовані!

  1. Додайте до нашого помічника програми наступний метод:

    module ApplicationHelper
        def include_related_asset(asset)
        #          v-----{Change this}
            if !YourApp::Application.assets.find_asset(asset).nil?
                case asset.split('.')[-1]
                    when 'js'
                        javascript_include_tag asset
                    when 'css'
                        stylesheet_link_tag asset
                end
            end
        end
    end
    
  2. Викличте допоміжний метод у своєму layout-file:

    <%= include_related_asset(params[:controller].to_param + '_' + params[:action].to_param . 'js') %>
    
  3. Створіть конкретні активи для дій вашого контролера. E. g.controller_action.js

Будь ласка, не забудьте змінити YourAppназву свого додатка.

Використовуйте yield

  1. Додайте <%= yield :head%>до голови макета
  2. Включіть свої активи з переглядів дій:

    <% content_for :head do %>
    <%= javascript_include_tag 'controller_action' %>
    <% end %>
    

Для отримання додаткової інформації див. Посібники Rails .


3

Мені подобається рішення albandiguer . За допомогою чого я переконався, що ресурси javascript / coffeescript не попередньо скомпільовані. Що спричиняє всілякі помилки при спробі використанняjavascript_path . Я поділюсь своїм рішенням цієї проблеми після того, як я розгляну проблему, яку кілька людей згадали в його коментарях. В основному мова йде лише про частковий набір контролера з іменем файлів JavaScript.

Тож я створив помічник програми, щоб виявити, чи існує файл у каталозі javascript незалежно від розширення .coffee / .js:

module ApplicationHelper
  def javascript_asset_path(basename)
    Sprockets::Rails::Helper.assets.paths.select{|i|
      i =~ /javascript/ and i =~ /#{Rails.root}/
    }.each do |directory|
      if Dir.entries(directory).map {|i| i.split('.')[0]}.compact.
          include? basename
        return File.join(directory, basename)
      end
    end
    nil
  end
end

Цей метод поверне повний шлях до файлу javascript, якщо він існує. В іншому випадку він повертає нуль. Отже, після коментаря Pencilcheck ви можете додати цей метод для умовного включення:

<%= javascript_include_tag(controller_name) if javascript_asset_path(controller_name) %>

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

# Live Compilation
config.assets.compile = true

Ви можете додати це, щоб зробити файл конфігурації вашого середовища. Спершу протестуйте його у своєму файлі середовища розробки. Знову ж це недоцільно. Конвеєр активів Rails використовує зірочки для оптимізації всього:

Зірочки завантажує вказані файли, обробляє їх, якщо це необхідно, об'єднує в один файл, а потім стискає (якщо значення Rails.application.config.assets.compress є). Обслуговуючи один файл, а не багато, час завантаження сторінок можна значно скоротити, оскільки браузер робить менше запитів. Стиснення також зменшує розмір файлу, дозволяючи браузеру швидше завантажувати їх.

БУДЬ ЛАСКА, ПРОЧИТАЙТЕ документацію для отримання детальної інформації про механіку зірочок (трубопровід активів) http://guides.rubyonrails.org/asset_pipeline.html

Активи попередньо не складаються окремо. Наприклад, коли я намагаюся:

<%= javascript_include_tag 'event' %>

Я отримав:

Зірочки :: Рейки :: Helper :: AssetFilteredError: Asset відфільтрована і не буде обслуговуватися: надбудова Rails.application.config.assets.precompile += %w( event.js )до config/initializers/assets.rbі перезапустити сервер

Таким чином, ви можете вказати, які активи потрібно попередньо скласти окремо. Нам просто потрібно додати відповідний контролер з іменем javascript files в наш ініціалізатор активів. Ну, ми можемо зробити це програмно.

Щоб отримати список імен контролерів, я скористаюся прикладом ecoologic :

all_controllers =  Dir[
    Rails.root.join('app/controllers/*_controller.rb')
  ].map { |path|
    path.match(/(\w+)_controller.rb/); $1
  }.compact

А тепер, щоб отримати ім'я всіх файлів javascript, які відповідають базовому імені імені контролера, ви можете використовувати наступне:

javascripts_of_controllers = Sprockets::Rails::Helper.assets.paths.select{|a_path|
    a_path =~ /javascript/ and a_path =~ /#{Rails.root}/
  }.map {|a_path|
    Dir.entries(a_path)
  }.flatten.delete_if {|the_file|
    !the_file['.js']
  }.collect {|the_file|
    the_file if all_controllers.any? {|a_controller| the_file[a_controller]}
  }

Тоді ви можете спробувати:

# config/initializers/assets.rb
Rails.application.config.assets.precompile += javascripts_of_controllers

Це дасть вам список усіх файлів javascript без шляху до каталогу, які відповідають імені вашого контролера. Зверніть увагу, якщо ваше ім’я контролера є множинним, ім’я javascript має бути також. Також зауважте, якщо контролер є одниною, а файл javascript є множинним, це все одно буде включати його черезthe_file[a_controller] буде успішним при частковому збігу.

Не соромтеся спробувати це у своєму Rails.application.config.assets.precompileналаштуванні. Я знаю, що це дає вам список файлів правильно. Але я залишу вас перевірити це. Повідомте мене, чи є якісь нюанси, пов’язані з попередньою компіляцією, як мені цікаво.

Для дуже детального пояснення того, як активізується попередня компіляція, див. Цей блог: http://www.sitepoint.com/asset-precompile-works-part/


куди слід помістити оператори all_controllers і javascripts_of_controllers?
Костянтин Воронов

1
Ну. я помістив обидва в свій ініціалізатор активів (assets.rb), але Sprockets :: Rails :: Helper.assets.paths тут був нульовим, тому мені довелося змінити його на Rails.application.config.assets.paths, все інше було нормально. дуже приємне рішення
Костянтин Воронов

1

Нещодавно я знайшов простий підхід до використання згенерованих сценаріїв для конкретного контролера. Я використовую для цього рішення gem gon . Додайте контролер:

class HomesController < ApplicationController
  before_filter :remember_controller

  private

  def remember_controller
    gon.controller = params[:controller]
  end
end

Після цього відкрийте homes.js.cofeeі додайте на початку файлу:

jQuery ->
  if gon.controller == "sermons"
    # Place all functions here...

Це все.

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