To my understanding, all of your JavaScript gets merged into 1 file. Rails does this by default when it adds //= require_tree .
to the bottom of your application.js
manifest file.
This sounds like a real life-saver, but I am a little concerned about page-specific JavaScript code. Does this code get executed on every page? The last thing I want is for all of my objects to be instantiated for every page when they are only needed on 1 page.
Also, isn't there potential for code that clashes too?
Or do you put a small script
tag at the bottom of the page that just calls into a method that executes the javascript code for the page?
Do you no longer need require.js then?
Thanks
EDIT: I appreciate all the answers... and I don't think they are really getting at the problem. Some of them are about styling and don't seem to relate... and others just mention javascript_include_tag
... which I know exists (obviously...) but it would appear that the Rails 3.1 way going forward is to wrap up all of your JavaScript into 1 file rather than loading individual JavaScript at the bottom of each page.
The best solution I can come up with is to wrap certain features in div
tags with id
s or class
es. In the JavaScript code, you just check if the id
or class
is on the page, and if it is, you run the JavaScript code that is associated with it. This way if the dynamic element is not on the page, the JavaScript code doesn't run - even though it's been included in the massive application.js
file packaged by Sprockets.
My above solution has the benefit that if a search box is included on 8 of the 100 pages, it will run on only those 8 pages. You also won't have to include the same code on 8 of the pages on the site. In fact, you'll never have to include manual script tags on your site anywhere ever again.
I think this is the actual answer to my question.
I see that you've answered your own question, but here's another option:
Basically, you're making the assumption that
is required. It's not. Feel free to remove it. In my current application, the first I'm doing with 3.1.x honestly, I've made three different top level JS files. My
application.js
file only hasThis way, I can create subdirectories, with their own top level JS files, that only include what I need.
The keys are:
require_tree
- Rails lets you change the assumptions it makesapplication.js
- any file in theassets/javascript
subdirectory can include pre-processor directives with//=
Hope that helps and adds some details to ClosureCowboy's answer.
Sujal
I don't see an answer that really puts it all together and lays it out for you. Thus, I'll try to put meleyal, sujal (a la ClosureCowboy), the first part of Ryan's answer, and even Gal's bold statement about Backbone.js... all together in a way that is short and clear. And, who knows, I might even meet Marnen Laibow-Koser's requirements.
Example edits
assets/javascripts/application.js
views/layouts/application.html.erb
views/foo/index.html.erb
assets/javascripts/foo.js
assets/javascripts/foostuff/foothis.js.coffee
Brief description
Remove
//= require_tree .
from application.js and list only the JS that each page shares.The two lines shown above in application.html.erb tell the page where to include application.js and your page-specific JS.
The three lines shown above in index.html.erb tells your view to look for some page-specific JS and include it at a named yield region called ":javascript" (or whatever you want to name it). In this example, the controller is "foo" so Rails will attempt to include "foo.js" at the :javascript yield region in the application layout.
List your page-specific JS in foo.js (or whatever the controller is named). List common libraries, a tree, directories, whatever.
Keep your custom page-specific JS someplace where you can easily reference it apart from your other custom JS. In this example, foo.js requires the foostuff tree so put your custom JS there, such as foothis.js.coffee.
There are no hard rules here. Feel free to move things around and perhaps even create multiple yield regions of various names in various layouts if needed. This just shows one possible first step forward. (I don't do it exactly like this given our use of Backbone.js. I might also choose to drop foo.js down into a folder called foo instead of foostuff but haven't decided that yet.)
Notes
You can do similar things with CSS and
<%= stylesheet_link_tag params[:controller] %>
but this is beyond scope of the question.If I missed a glaring best practice here, send me a note and I'll conisder adapting. Rails is fairly new to me and, honestly, I'm not terribly impressed so far with the chaos it brings by default to enterprise development and all the traffic the average Rails program generates.
I appreciate all the answers... and I don't think they are really getting at the problem. Some of them are about styling and don't seem to relate... and others just mention
javascript_include_tag
... which I know exists (obviously...) but it would appear that the Rails 3.1 way going forward is to wrap up all of your Javascript into 1 file rather than loading individual Javascript at the bottom of each page.The best solution I can come up with is to wrap certain features in
div
tags withid
s orclass
es. In the javascript code. Then you just check if theid
orclass
is on the page, and if it is, you run the javascript code that is associated with it. This way if the dynamic element is not on the page, the javascript code doesn't run - even though it's been included in the massiveapplication.js
file packaged by Sprockets.My above solution has the benefit that if a search box is included on 8 of the 100 pages, it will run on only those 8 pages. You also won't have to include the same code on 8 of the pages on the site. In fact, you'll never have to include manual script tags on your site anywhere ever again - except to maybe preload data.
I think this is the actual answer to my question.
First: remove
\\=require_tree
from application.js Second: all your JS code must be alocated at/app/assets/javascritpt
and all your CSS code must be alocated at/app/assets/stylesheets
Another option: to create page- or model-specific files, you could create directories inside your
assets/javascripts/
folder.Your main
application.js
manifest file could be configured to load its files fromglobal/
. Specific pages or groups of pages could have their own manifests which load files from their own specific directories. Sprockets will automatically combine the files loaded byapplication.js
with your page-specific files, which allows this solution to work.This technique can be used for
style_sheets/
as well.