Shalafister's
Shalafister's

Reputation: 881

Rails js files & Page specific js

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?

Upvotes: 13

Views: 9451

Answers (3)

AnkurVyas
AnkurVyas

Reputation: 259

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.

Upvotes: 2

Jeremy
Jeremy

Reputation: 675

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.");
});

Upvotes: 9

Mat
Mat

Reputation: 2184

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 %>

Upvotes: 12

Related Questions