Предисловие
Если вы используете Rails >= 3.1 с включенным asset pipeline, то конечно знаете, что все скрипты под директивой
require_tree
(а речь пойдет именно о них) сжимаются в один файл и, соответственно, отрабатывают на всех страницах. Но что делать, если кусок джаваскрипта нужен только на одной странице и совсем не нужен на другой? Почему джем
Ведь существуют и другие способы (надеюсь, никто не пишет код во вью). Самый очевидный, пожалуй, – написать в требуемом шаблоне:
<% content_for :head do %>
<%= javascript_include_tag 'my_fancy_js' %>
и исключить файл из
require_tree
. Но минус такого подхода в том, что скрипты, относящиеся определенному контроллеру, не находятся в одном месте (а значит тяжелее искать и разбираться). В довесок, если кусок кода большой, то мы теряем преимущества пайплайна. Решение, используемое в джеме, сводит до минимума описанные недостатки.Как это работает
Вы выбираете котроллер и экшны, в которых необходим кастомный скрипт, и запускаете генератор:
rails generate pluggable_js Post index new
Он сгенерит два файла, в которых будут вызываться функции
Post.index()
и Post.new()
, после того как загрузится DOM:app/assets/javascripts/pluggable/posts/index.js.coffee
app/assets/javascripts/pluggable/posts/new.js.coffee
Теперь вам осталось просто описать их в posts.js.coffee:
window.Post ||= {}
Post.index = () ->
# your code goes here
Post.new = () ->
# and here
А хелпер
<%= javascript_pluggable_tag %>
, прописанный в лейауте, подключит файл, если сопоставит путь и значения текущих параметров контроллер/экшн. Да, происходит дополнительный запрос на сервер, но это всего лишь триггер.* Я опустил необязательные для описания идеи тонкости, поэтому см. подробную инструкцию.
Конфиг
Предположим, вы создали экшн search, который (как и экшн index) рендерит шаблон index. Получается, что функцию
Post.index()
также необходимо вызвать. Для этого можно создать config/initializers/pluggable_js.rb и воспользоваться настройкой:PluggableJs.config do |config|
config.pair_actions = { 'search' => 'index' }
end
{ 'create' => 'new', 'update' => 'edit' }
прописаны по умолчанию.В итоге
Все скрипты, относящиеся к контроллеру, находятся в одном месте. Все кастомные функции попадают в пайплайн. И, наконец, мы полностью очистили вью от каких-либо упоминаний о js.
UPD: Всем спасибо за комментарии. Внимание, обновил джем, теперь не нужно ничего добавлять в config.assets.precompile. Достаточно просто объявить функции. Осталось подумать над ролями. Посмотрите на джем styx, как на альтернативное решение.
Спасибо verybigman, ExReanimator и owls за вклад.