Skip to content Skip to sidebar Skip to footer

How To Do Per-page Javascript With The Rails Asset Pipeline

I understand that for performance reasons it is better to let the asset pipeline concatenate and minify all my javascript and send the whole lot with every page request. That's fa

Solution 1:

Here is what I do (based on some stackoverflow answers):

application_helper.rb

def body_page_name
  [controller_name.classify.pluralize, action_name.classify].join
end

application.html.haml

  %body{data: {page: body_page_name}}

application.js

$(function() {
  var page = $("body").data("page");
  if("object" === typeof window[page])
    window[page].init();
});

And in appropriate js file there's an object called ControllerAction:

tickets.js

var TicketsShow = new function() {
  var self = this;

  self.init = function() {
    // code which may call other functions in self
  };
};

There's probably better way to do it, but this works for me


Solution 2:

I'll describe what I currently do, just in case it gives anyone a better idea

1) I changed the 'body' tag in my application.html.erb to add the current controller and action as data- attributes

<body data-controller="<%= controller.controller_name %>"
  data-action="<%= controller.action_name %>" >

2) I test this at the top of the relevant javascript

$(document).ready(function() {
        if($('body').data('controller')=='stories') {
            $('.story').click(function(e) {
                    var u=$(this).data('url');
                    u && (document.location=u);
            });
        }
    });

I can't decide if I think this is a good idea or not


Solution 3:

For page specific JavaScript, I typically do something like this:

Application Helper

In the application helper I create a class attribute (though you could just as well use a data attribute instead).

module ApplicationHelper
  def body_attributes
    controller = params[:controller].gsub('/', ' ')
    action = params[:action]
    version = @version ? "version_#{@version}" : nil
    {
      class: ([controller, action, version] - [nil]).join(' ')
    }
  end
end

Note I'm also adding a version string. This helps with Google content experiments, and makes A/B testing a breeze.

Application.html.haml

In my global layout file, I do something like this to insert the attributes on the body tag:

!!! 5
%html
  %head
    ...
  %body{body_attributes}

script.js

Now in my page specific script, I just check for the class attributes, like this:

$(function () {
  if ($('body.pledge.new, body.pledge.create').length > 0) {
    // do work here...
  }
});

The advantage of this method is that getting the body by class is very quick. The script inside the conditional will not be executed at all on any page apart than the ones I choose, so minimal overhead, and I don't need to change my selectors throughout the code.

EDIT

Note that this answer is now 3 years old. You should be using client-side routing with a framework like React instead.


Solution 4:

I'd add a class to the BODY tag, allowing you to identify each page, and therefore each control per page.

<body class='page1'>

JS:

$('.page1 button').click(function(e) { $('input.sel').val(this.name); }

Solution 5:

I've done it and seen it done in several different ways:

  1. Rigging up the mvc to be able to load a particular js file per page, named along the same lines as a controller file. Like: <controller-name>.js

  2. Making a url parser in JS and then setting a global variable to the current page: UrlParams.currentView = 'dashboard'; and then saying if(UrlParams.currentView == 'dashboard') { //do specific js here }

  3. Setting a unique identifier as the page class or ID and then targeting that with your JS selectors. $('#dashboard').xyz();


Post a Comment for "How To Do Per-page Javascript With The Rails Asset Pipeline"