2

The rails asset pipeline has it's issues, but the benefits of concatenating all my JS, minifying it and serving it with far-future expires headers are hard to ignore.

Lots of the JS in my rails app is specific to a single action. For example, we have a complex page for staff to enter customer orders.

pre rails 3.1, I had the action-specific code in a distinct JS file that was only loaded when needed. Now all my JS is served all the time. What's the best way to only run the order-entry JS when it's needed?

Currently I'm checking for the order-entry DOM elements, but that means there'll be lots of unnecessary functions running on DOMready.

Here's a snippet of coffeespcript from the order-entry code, and this pattern is repeated in about 20 files. Is there a better way?

$ ->
  window.app.draft = new app.DraftOrder()

@module 'app', ->
  class @DraftOrder
    constructor: ->
      @items = $('table.draft-items tr')
      return if @items.size() == 0
      @initEvents()
      @move_first()
    initEvents: ->
      # foo
    otherMethod: ->
      # bar
Dairo
  • 822
  • 1
  • 9
  • 22
James Healy
  • 14,557
  • 4
  • 33
  • 43
  • 1
    after submitting this question I found http://stackoverflow.com/questions/6133235/rails-3-1-rc1-javascript-and-asset-pipeline - probably makes mine a dupe – James Healy Dec 05 '11 at 23:32

2 Answers2

2

I like to wrap my page-specific JS in a closure, and insert code in my application template that lets me selectively execute it.

so, my page-specific js for an "Events" controller might look like:

events = {
  onload: function() {
    // put any page-specific onload code here
  },
  someOtherRoutine: function() {
  }
}

in my application template (application.html.erb), I add:

<%= javascript_tag do %>
  window.controller_name = <%= params[:controller] %>;
  window.action_name = <%= params[:action] %>;
<% end%>

then, in application.js (assuming you use jQuery):

$(function() {
  if(controller_name === 'events'){
    events.onload();
  }
  else if(controller_name === 'anothercontroller'){
    anothercontroller.onload();
  }

  // put any global onload functionality here...
});

This has the additional advantage of giving a sort of poor-man's namespacing to all of your page-specific JS.

There's probably a more idiomatic rails/javascript way to do this; I'm not primarily a JS programmer but I am learning to like the language quite a bit...

Drew Shafer
  • 4,740
  • 4
  • 30
  • 42
0

It is including all of your javascript files only because you have this line in your application.js file:

//= require_tree .

If you take that out, it will only include the files that you specifically require. If you specify the name of a folder (rather than .), then you can have a spot where you put files that you want to be 'auto-included'. You can read more about this in the Rails Guides. For example, your application.js file could look like this:

//= require jquery_ujs
//= require main

Then, you could have an order_entry.js file that just has the code you want in it. Of course, you link to these the same way you used to:

For application.js:

<%= javascript_include_tag "application" %>

For your new order_entry.js:

<%= javascript_include_tag "order_entry" %>
dontangg
  • 4,729
  • 1
  • 26
  • 38