yerforkferchips
yerforkferchips

Reputation: 1985

Why does the Rails asset pipeline not work surprise-free with subdirectories?

I'm using Rails 3.2, and am somewhat confused about the handling of subdirectories and relative paths of the asset pipeline.

My situation

I'm trying to include four code files in (javascripts/edit), one of them being in the subdirectory javascripts/edit/ckeditor, in a manifest file, (javascripts/edit/all.js). I'm not including these in the application.js because I want to include these scripts only on certain pages.

Doing //= require ckeditor/ckeditor doesn't work. Doing //= require mycode (to require javascripts/edit/mycode.js), too, doesn't work, apparently because mycode.js is in the "edit" subdirectory of the javascripts "root" folder. To make it work, I had to put this:

//= require ./ckeditor/ckeditor
//= require ./json2
//= require ./cssjson
//= require ./mycode

inside of my manifest all.js. Note that this:

//= require edit/ckeditor/ckeditor
//= require edit/json2
//= require edit/cssjson
//= require edit/mycode

works exactly the same, even though all.js itself is already in the edit subdirectory.

So my question is, why does this work this way? I would expect to be able to put manifest files in subdirectories and just include files that are in that same subdirectory (e.g. //= require json2), but apparently, all //= require directives in any file below app/assets/javascripts always are relative to that "root" folder, not the subdirectory that the manifest files are in.

Upvotes: 1

Views: 150

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

So my question is, why does this work this way?

Because when Rails compiles the assets, it's compiling from a central point, not your subdirectory. The manifest system works based on the assets' root path (the documentation says The first feature of the pipeline is to concatenate assets), consequently your assets will be compiled from the application.js file

You have to remember when Rails runs, it's not loading the assets dynamically. It's designed to load application.css / application.js all the time, and it's then up to the developer to delegate assets which they wish to load on specific pages

The way we do this is to include all the "constant" files in our application.js file, and then load controller-specific assets in the layout. This allows us to only call things like JQuery all the time, whilst we may call specific JQuery plugins for certain controllers:


Including The Right Assets In The Right Places

This is what we do:

#app/views/layouts/application.html.erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag controller_name, media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag controller_name, "data-turbolinks-track" => true %>


#app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery.ui.draggable
//= require_tree ./jquery
//= require_tree ./extra
//= require turbolinks

#app/assets/javascripts/users.js.erb
//= require ** anything you want **

This allows you to have a lot more control over which assets you're loading

Upvotes: 2

Related Questions