13

On rails I put all the JavaScript files into application js file.

//= require jquery
//= require jquery_ujs
//= require dropzone
//= require jquery.cookie
//= require toastr

//VENDOR JS BEGINS
//= require pace/pace.min
//= require modernizr.custom
//= require jquery-ui/jquery-ui.min
//= require boostrapv3/js/bootstrap.min
//= require jquery/jquery-easy
//= require jquery-unveil/jquery.unveil.min
//= require jquery-bez/jquery.bez.min
//= require jquery-ios-list/jquery.ioslist.min
//= require jquery-actual/jquery.actual.min
//= require jquery-scrollbar/jquery.scrollbar.min
//= require bootstrap-select2/select2.min
//= require switchery/js/switchery.min
//= require imagesloaded/imagesloaded.pkgd.min
//= require jquery-isotope/isotope.pkgd.min
//= require classie/classie
//= require codrops-stepsform/js/stepsForm
//= require bootstrap-datepicker/js/bootstrap-datepicker

Then I call javascript in the head of application.html.erb as;

...
<head>
..
<%= javascript_include_tag 'application' %>    
..
</head>
...

Then I check the speed of the website and I am suggested to take this JS call to body. I know I should BTW. But the problem is with the page specific JS code.

Imagine I have home.html.erb where users select date. So I put datapicker code into this page.

If I take <%= javascript_include_tag 'application' %> into at the bottom of body, this time because the jquery & datepicker not loaded yet so page specific JS gives no method error

What would be the best approach?

1
  • I'm guessing you're not using turbolinks? If you're not, it means you're loading the entire html(including assets) for each navigation. If that is the case I think your first priority should be how to load everything only once (like with turbolinks or ajax apps like angular) if you want to improve performance. Commented Dec 20, 2016 at 8:59

3 Answers 3

12

Before body close tag and just after <%= javascript_include_tag 'application' %>

add <%= yield :page_scripts %>

Then anywhere (usually on top) in a specific view set your scripts with:

<% content_for :page_scripts do %>
  <script>alert( "My nice scripts..." );</script>
<% end %>
Sign up to request clarification or add additional context in comments.

Comments

9

There is a very good answer to this at http://brandonhilkert.com/blog/page-specific-javascript-in-rails/.

Basically, you want to open your app/views/layouts/application.html.erb and convince it to give you controller and view information each time it renders a page. To do so you change the body tag from

<body> 
  <%= yield %>
</body

to

<body class="<%= controller_name %> <%= action_name %>">
  <%= yield %>
</body>

So, when rails renders the body tag it will now add a class for the controller and one of the actions in the controller.

Say you have a controller called static_pages, and the static_pages controller has

def home 
end

When rails renders the view/page home it will now add to the body tag a class of static_pages and a class of home.

<body class="static_pages home">
    the home view is rendered here
</body>

This will be a site wide change, so if you go to an index page/view from the users controller the body tag would be:

<body class="users index">
    the index view is rendered here
</body>

Now, make a file called vendor/assets/javascripts/jquery-readyselector.js containing:

(function ($) {
  var ready = $.fn.ready;
  $.fn.ready = function (fn) {
    if (this.context === undefined) {
      // The $().ready(fn) case.
      ready(fn);
    } else if (this.selector) {
      ready($.proxy(function(){
        $(this.selector, this.context).each(fn);
      }, this));
    } else {
      ready($.proxy(function(){
        $(this).each(fn);
      }, this));
    }
  }
})(jQuery);

That file must be properly referenced in application.js

...
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require jquery-readyselector
//= require_tree . 

Once all that is done you can test it by making a simple alert specific to the view you want test like so:

// app/assets/javascripts/static_pages_home.js

$(".static_pages.home").ready(function() {
  return alert("You should only see this on the static pages home page.");
});


// app/assets/javascripts/user_index.js

$(".users.index").ready(function() {
  return alert("You should only see this on the users index page.");
});

You could also make a script controller specific by not referencing the action.

$(".users").ready(function() {
  return alert("You should only see this on a users controller controlled page.");
});

2 Comments

Do you have to add the javascript tag in the body ?
2

You can also have a look at Page-specific Javascript for Rails done right. This is worth looking!

Installation

After installation. Let's look at sample code.

var ArticlesController = Paloma.controller('Articles');

ArticlesController.prototype.edit = function(){
  // Handle edit article
};

That means that if you have Articles controller's edit action page. Then only the javascript will be triggered. This will not be triggered in other controller actions.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.