how should I include a coffeescript file on only one page?

14,111

Solution 1

Rather than only including the file on one page, you might want to just use logic that's conditional on the page markup. See my answer to a related question. That way, your users don't have to make an additional <script> request for the particular page.

If there's a lot of logic specific to that page (say, 10K+ minified), then yes, split it out. As you suggested in the edit to your question: Rather than doing require_tree . at the root of your javascripts directory, instead create a sub-directory called global and change the top of application.js from

require_tree .

to

require_tree global

Then put your page-specific CoffeeScript file in the root javascripts directory, and point to it with a javascript_include_tag call in that page's template.

Solution 2

Here's the approach I use to make controller/view specific Coffee:

application.html.haml:

%body{ :data => { :controller => params[:controller], :action => params[:action]} }

alt. application.html.erb

<%= content_tag(:body, :data => { :controller => params[:controller], :action => params[:action] }) do %>
  ...
<% end %>

application.js.coffee:

$(document).ready ->
  load_javascript($("body").data('controller'),$("body").data('action'))

load_javascript = (controller,action) ->
  $.event.trigger "#{controller}.load"
  $.event.trigger "#{action}_#{controller}.load"

users.js.coffee

$(document).bind 'edit_users.load', (e,obj) =>
  # fire on edit users controller action

$(document).bind 'show_users.load', (e,obj) =>
  # fire on show users controller action

$(document).bind 'users.load', (e,obj) =>
  # fire on all users controller actions

Sidenote:

This works great with PJAX as well as you can pass the controller/action names with the response header on PJAX requests and just fire these js functions based on that.

EDIT (2014/03/04): This solution still works when using turbolinks.js.

Share:
14,111

Related videos on Youtube

jcollum
Author by

jcollum

Updated on June 04, 2022

Comments

  • jcollum
    jcollum almost 2 years

    Edit: a year later if I was going to do this again I'd do it with curl.js instead of Rails asset pipeline.

    Related: Best way to add page specific javascript in a Rails 3 app?

    I'm writing an app and using coffeescript to generate all of the js. That's why the related question doesn't do what I need.

    I'd like to be able to put a coffeescript file in a subfolder of my assets directory and have that .coffee file only get served up on one page. The page is on a named route

    match 'myNotifications' => 'user#notifications'

    The most obvious thing to do was to put the .coffee file in assets\javascripts\user\index.js.coffee. But after reading the docs about assets I'm unclear.

    I read this line (from http://guides.rubyonrails.org/asset_pipeline.html):

    You should put any JavaScript or CSS unique to a controller inside their respective asset files, as these files can then be loaded just for these controllers with lines such as <%= javascript_include_tag params[:controller] %> or <%= stylesheet_link_tag params[:controller] %>.

    Ok cool, so I put the page specific js in assets\javascripts\user.js.coffee. Then I reloaded my home page, Ctrl F5. The user.js file is still being loaded on the homepage. Tested with $ -> alert 'ready from users controller'; seeing that alert when I load the homepage.

    Does Rails have a way to have a per-page coffeescript file that will only be served up with that page? Am I reading the manual wrong? Is there a place in the assets folder that I can put .coffee files where they won't get loaded with every page?

    Update: Looks like I might have an answer:

    There are a couple of ways that we can get around this problem. We could use require_directory instead of require_tree as this will only load the files in the current directory and not in subdirectories. If we want more control over the included files we can require them separately instead of including the whole directory. Alternatively we could move the JavaScript files that we want to be included on all pages into a public subdirectory. We can then use require_tree ./public to include just those files.

    I'll give that a shot in the AM.

    • rhardih
      rhardih
      Since I had the same problem, I decided to gather some different solutions I ran across in one place and did a small write-up here: page-specific-javascript-in-rails-3
  • jcollum
    jcollum over 12 years
    I'm starting to see the logic of one big js file. This post says that there is a significant loading hit to having many js and css files: rubyrobot.org/article/5-tips-for-faster-loading-web-sites
  • Trevor Burnham
    Trevor Burnham over 12 years
    Right. As I say, the advantage of splitting it out is that if that specific page has a ton of JS, you don't want people to have to download that when they load your home page. A third alternative is to use an asynchronous JS loader so that people who come to your home page load the scripts they need first, then all the rest after the page has loaded, so they'll be cached when they visit your other pages.
  • Mitziu Echeverria
    Mitziu Echeverria about 12 years
    I'm using Rails 3.2 and it asked me to list the require_tree directory as a relative path so I used "require_tree ./global" and I was all set.
  • berto77
    berto77 about 11 years
    Nice technique. Somehow I prefer regular jQuery/JavaScript to coffee. too much abstraction.