Rectangle 27 21

%body{ :data => { :controller => params[:controller], :action => params[:action]} }
<%= content_tag(:body, :data => { :controller => params[:controller], :action => params[:action] }) do %>
  ...
<% end %>
$(document).ready ->
  load_javascript($("body").data('controller'),$("body").data('action'))

load_javascript = (controller,action) ->
  $.event.trigger "#{controller}.load"
  $.event.trigger "#{action}_#{controller}.load"
$(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

ruby on rails - how should I include a coffeescript file on only one p...

ruby-on-rails ruby-on-rails-3 coffeescript
Rectangle 27 21

%body{ :data => { :controller => params[:controller], :action => params[:action]} }
<%= content_tag(:body, :data => { :controller => params[:controller], :action => params[:action] }) do %>
  ...
<% end %>
$(document).ready ->
  load_javascript($("body").data('controller'),$("body").data('action'))

load_javascript = (controller,action) ->
  $.event.trigger "#{controller}.load"
  $.event.trigger "#{action}_#{controller}.load"
$(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

ruby on rails - how should I include a coffeescript file on only one p...

ruby-on-rails ruby-on-rails-3 coffeescript
Rectangle 27 9

<script>

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

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

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.

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.

ruby on rails - how should I include a coffeescript file on only one p...

ruby-on-rails ruby-on-rails-3 coffeescript
Rectangle 27 9

<script>

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

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

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.

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.

ruby on rails - how should I include a coffeescript file on only one p...

ruby-on-rails ruby-on-rails-3 coffeescript
Rectangle 27 21

There are two common approaches:

Make behavior conditional on the presence of a particular element. For instance, code to run a signup sheet should be prefaced with something like

if $('#signup').length > 0

Make behavior conditional on a class on the body element. You can set the body class using ERB. This is often desirable for stylesheets as well. The code would be something like

if $('body').hasClass 'user'

Thanks, I'll give them both a try, might also try to do something with namespacing, I think I have a better idea of how to handle that without introducing bare

Of course, you should probably be starting every file with $ -> anyway (jQuery's new-ish shorthand for the classic $(document).ready), which makes bare superfluous...

Nope @LucasPottersky, that's pretty ugly. I can't believe a better solution isn't part of Rails code. Or is it by now?

ruby on rails 3.1 - How do I associate a CoffeeScript file with a view...

coffeescript ruby-on-rails-3.1
Rectangle 27 47

By default, every CoffeeScript file is compiled down into a closure. You cannot interact with functions from a different file, unless you export them to a global variable. I'd recommend doing something like this:

On top of every coffeescript file, add a line like

window.Application ||= {}

Now, for every function that you'll have the need to call from another file, define them as

Application.indicator_tag = (el) ->
  ...

and call them using

Application.indicator_tag(params)

Dogbert's answer is correct. (Note that you could also use this/@ to export variables as globals in this case, e.g. @indicator_id = ..., since CoffeeScript's wrapper is called in the global context). The reason you're just bumping into that now is that earlier versions of Rails 3.1 disabled CoffeeScript's wrapper. This behavior was classified as a bug and fixed for RC1: github.com/rails/rails/issues/1125

Ah, thank you so much. My entire app was broken haha.

javascript - "Can't find variable" error with Rails 3.1 and Coffeescri...

javascript ruby-on-rails coffeescript
Rectangle 27 1

The file is indeed being run through ERB, but only once - when the application is precompiling assets. And this isn't something you can change very easily, and you probably shouldn't try.

What you could do instead is fetch the actual data that you want populated separately via an AJAX JSON request or maybe embed it as Javascript in your page template.

The ERB compilation of static (CSS + JS) files is normally used to put in environment specific data that doesn't change with each request.

ruby on rails - erb won't render in coffeescript file - Stack Overflow

ruby-on-rails coffeescript erb
Rectangle 27 25

a couple of ways I have done this in the past

put the data in hidden fields, access the data in js/coffee

# single value
<%= hidden_field_tag "foo_name", @foo.name, { :id => "foo-name" } %>
$('#foo-name').val();

# when the 'value' has multiple attributes
<%= hidden_field_tag "foo", @foo.id, { :id => "foo", "data-first-name" => @foo.first_name, "data-last-name" => @foo.last_name } %>
$foo = $('#foo')
console.log $foo.val()
console.log $foo.data("firstName")
console.log $foo.data("lastName")

another option: load data into js data structure in erb, access it from js/coffee

<% content_for(:head) do %>
    <script>
    window.App = window.App || {};
    window.App.Data = window.App.Data || {};
    window.App.Data.fooList = [
        <% @list.each do |foo| %>
            <%= foo.to_json %>,
        <% end %>
    ];
    </script>
<% end %>


# coffee
for foo in window.App.Data.fooList
    console.log "#{foo.id}, #{foo.first_name} #{foo.last_name}"

I am not a big fan of constructing javascript data from ruby in erb like this, something about it just feels wrong - it can be effective though

and another option: make an ajax call and get the data on-demand from the server

I am also interested in other ideas and approaches

If you need to run loops and construct json you could use a before_filter which runs a method to construct a single JSON object and assign it to an instance variable. Then you simply output the one instance variable in your view's Javascript assignment. I find this better than ajax because it's one less HTTP request.

Rails: access controller instance variable in CoffeeScript or JavaScri...

ruby-on-rails controller coffeescript erb instance-variables
Rectangle 27 15

A more Rails way is to use a helper. This allows you to check for a coffeescript or a javascript version of a file:

Then you can use it in your layout:

<%= javascript_include_tag params[:controller], :media => "all"  if javascript_exists?(params[:controller]) %>

You can do the same with your CSS:

-- helper --
 def stylesheet_exists?(stylesheet)
   stylesheet = "#{Rails.root}/app/assets/stylesheets/#{params[:controller]}.css"
   File.exists?(stylesheet) || File.exists?("#{stylesheet}.scss") 
 end

 -- layout --
 <%= stylesheet_link_tag params[:controller], :media => "all"  if stylesheet_exists?(params[:controller]) %>
javascript_exists?
def javascript_exists?(script)
  script = "#{Rails.root}/app/assets/javascripts/#{script}.js"
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#{script}#{extension}")
  end
end

call it in the application layout:

<%= javascript_include_tag params[:controller]  if javascript_exists?(params[:controller]) %>

This will now handle more extensions and use an inject to determine if the file exists. You can then add a bunch more extensions to the extensions array, as needed for your app.

Same, but for stylesheets:

def stylesheet_exists?(stylesheet)
  stylesheet = "#{Rails.root}/app/assets/stylesheets/#{stylesheet}.css"
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#{stylesheet}#{extension}")
  end
end
def asset_exists?(subdirectory, filename)
  File.exists?(File.join(Rails.root, 'app', 'assets', subdirectory, filename))
end

def image_exists?(image)
  asset_exists?('images', image)
end

def javascript_exists?(script)
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('javascripts', "#{script}.js#{extension}")
  end
end

def stylesheet_exists?(stylesheet)
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('stylesheets', "#{stylesheet}.css#{extension}")
  end
end

asset pipeline - In Rails how to check if javascript file exists befor...

ruby-on-rails-3 asset-pipeline
Rectangle 27 15

A more Rails way is to use a helper. This allows you to check for a coffeescript or a javascript version of a file:

Then you can use it in your layout:

<%= javascript_include_tag params[:controller], :media => "all"  if javascript_exists?(params[:controller]) %>

You can do the same with your CSS:

-- helper --
 def stylesheet_exists?(stylesheet)
   stylesheet = "#{Rails.root}/app/assets/stylesheets/#{params[:controller]}.css"
   File.exists?(stylesheet) || File.exists?("#{stylesheet}.scss") 
 end

 -- layout --
 <%= stylesheet_link_tag params[:controller], :media => "all"  if stylesheet_exists?(params[:controller]) %>
javascript_exists?
def javascript_exists?(script)
  script = "#{Rails.root}/app/assets/javascripts/#{script}.js"
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#{script}#{extension}")
  end
end

call it in the application layout:

<%= javascript_include_tag params[:controller]  if javascript_exists?(params[:controller]) %>

This will now handle more extensions and use an inject to determine if the file exists. You can then add a bunch more extensions to the extensions array, as needed for your app.

Same, but for stylesheets:

def stylesheet_exists?(stylesheet)
  stylesheet = "#{Rails.root}/app/assets/stylesheets/#{stylesheet}.css"
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || File.exists?("#{stylesheet}#{extension}")
  end
end
def asset_exists?(subdirectory, filename)
  File.exists?(File.join(Rails.root, 'app', 'assets', subdirectory, filename))
end

def image_exists?(image)
  asset_exists?('images', image)
end

def javascript_exists?(script)
  extensions = %w(.coffee .erb .coffee.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('javascripts', "#{script}.js#{extension}")
  end
end

def stylesheet_exists?(stylesheet)
  extensions = %w(.scss .erb .scss.erb) + [""]
  extensions.inject(false) do |truth, extension|
    truth || asset_exists?('stylesheets', "#{stylesheet}.css#{extension}")
  end
end

asset pipeline - In Rails how to check if javascript file exists befor...

ruby-on-rails-3 asset-pipeline
Rectangle 27 8

There is a really nice rail cast and quite recent (feb. 2012) about this specific topic: #324 Passing Data to JavaScript

It shows 3 ways: a script tag, a data attribute, and the Gon gem. I think house covered all the available techniques. I would only mention that using an AJAX call is best used when you have a large volume of data, dynamic data or combination of both.

Rudolph, open the RailsCast and it also shows code examples. Better examples than I could ever give :)

I opened, I saw, but answers are supposed to be self contained with all pertinent example code (i.e. not require you to access another page in order to get pertinent information)...

The techniques mentioned are the same as those for passing variables to Js in views: stackoverflow.com/questions/2464966/

This was the best answer. I added an answer that included examples using gon, but my edit approval rating is so low I just reposted it as an answer.

Rails: access controller instance variable in CoffeeScript or JavaScri...

ruby-on-rails controller coffeescript erb instance-variables
Rectangle 27 5

Rather than use a hidden field I chose to add a data attribute to the container div which jquery can pick up.

<div class="searchResults" data-query="<%= @q %>"></div>
url: "/search/get_results?search[q]=" + $(".searchResults").data("query") + "&page=" + p

I feel this is the cleanest way to pass data to javascript. After having found no way to pass a variable to a coffee script file with the rails asset pipeline from a controller. This is the method I now use. Can't wait till someone does set up the controller way with rails that will be the best.

Rails: access controller instance variable in CoffeeScript or JavaScri...

ruby-on-rails controller coffeescript erb instance-variables
Rectangle 27 1

In situations where your javascript data gets out of hand, using the gon gem is still the preferred way to go in rails, even in 2015. After setting up gon, you are able to pass data to your javascript files by simply assigning the data to the gon object in rails.

(Gemfile)
gem 'gon'

(controller) 
def index 
  gon.products = Product.all 

(layouts) 
<%= include_gon %> 

(public/javascripts/your_js_can_be_here.js) 
alert(gon.products[0]['id'); 

(html source automatically produced) 
<script> 
  window.gon = {}; 
  gon.products = [{"created_at":"2015", "updated_at":"2015, "id":1, "etc":"etc"}];

You can read more verbose implementation details on Gon or the two other rails-javascript channels from Ryan Bate's screencast.http://railscasts.com/episodes/324-passing-data-to-javascript

Rails: access controller instance variable in CoffeeScript or JavaScri...

ruby-on-rails controller coffeescript erb instance-variables
Rectangle 27 3

@foo_attr = { "data-foo-1" => 1, "data-foo-2" => 2 }
#foo{@foo_attr}
$("#foo").data("foo-1")
$("#foo").data("foo-2")

Rails: access controller instance variable in CoffeeScript or JavaScri...

ruby-on-rails controller coffeescript erb instance-variables
Rectangle 27 2

Either of the places you've suggested (application.js or a specific coffeescript file) are valid - though it should be written in the coffee syntax if you're putting it in a coffeescript file.

You need to put that code within a $(document).ready function to get it to work...

$(document).ready(function() {
  $("p").hide();
  $("a").click(function ( event ) {
    event.preventDefault();
    $(this).hide();
  });
});

Rails 3.1 rc4 and Jquery: beginner's question - Stack Overflow

jquery ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1
Rectangle 27 22

CoffeeScript compiles to JavaScript on demand when a request is made to a view that includes a CoffeeScript resource.

However, you can use the following to have CoffeeScript compile to JavaScript ahead of time:

rake assets:precompile

The file extensions used on an asset determine what preprocessing is applied. When a controller or a scaffold is generated with the default Rails gemset, a CoffeeScript file and a SCSS file are generated in place of a regular JavaScript and CSS file. The example used before was a controller called projects, which generated an app/assets/javascripts/projects.js.coffee and an app/assets/stylesheets/projects.css.scss file.

When these files are requested, they are processed by the processors provided by the coffee-script and sass-rails gems and then sent back to the browser as JavaScript and CSS respectively.

Assets are compiled and cached on the first request after the server is started. Sprockets sets a must-revalidate Cache-Control HTTP header to reduce request overhead on subsequent requests on these the browser gets a 304 (Not Modified) response.

If any of the files in the manifest have changed between requests, the server responds with a new compiled file.

Rails comes bundled with a rake task to compile the asset manifests and other files in the pipeline to the disk.

Compiled assets are written to the location specified in config.assets.prefix. The default setting will use the public/assets directory.

You must use this task either during deployment or locally if you do not have write access to your production filesystem.

The rake task is:

RAILS_ENV=development bundle exec rake assets:precompile

This is all about production env right? What about development env?

javascript - When does Rails compile CoffeeScript? - Stack Overflow

javascript ruby-on-rails ruby-on-rails-3 coffeescript
Rectangle 27 1

I managed to do it withOUT an "index.js.erb" file in Rails 4. Just add this coffeescript:

$(window).on 'scroll', ->
  if $('.pagination').length
    @url = $('.pagination .next_page').attr('href')
    if url && $(window).scrollTop() > $(document).height() - $(window).height() - 50
      $('.pagination').remove()
      $('#articles').append('<div>')
      $('#articles div').last().load @url+' #articles', ->
          if $('.next_page.disabled').length
            $('.pagination').remove()

This loads the next page then uses the pagination on the newly loaded page until there are no more next pages. Just replace "#articles" with the id of your container in the script. Skip the index.js.erb and respond_to jazz.

javascript - jQuery Endless page with will_paginate not working in Rai...

javascript jquery ruby-on-rails-3 coffeescript will-paginate
Rectangle 27 2

Best way (and cleanest) I figured out is to add the javascript to the asset pipeline. This will ensure that JQuery is available. So something like this in some coffeescript file:

$('#map').mappy()

Where you define the JQuery plugin Mappy like this:

(($, window) ->

    class Mappy
        # defaults:
        constructor: (el, options) ->
            @$el = $(el)
            # @options = $.extend({}, @defaults, options)

            @id         = @$el.attr 'id'
            @lat        = @$el.data 'lat'
            @lng        = @$el.data 'lng'
            @markers    = @$el.data 'markers'
            @handler    = Gmaps.build 'Google', { builders: { Marker: RichMarkerBuilder }, markers: { maxRandomDistance: null } }

            @handler.buildMap
                provider: {}
                internal:
                    id: @id
            , =>
                json = @markers
                if json
                    markers = @handler.addMarkers json
                    @handler.bounds.extendWith markers
                    @handler.fitMapToBounds()
                    if json.length == 1
                        @handler.getMap().setZoom $.LOCATIONS_DEFAULT_ZOOM
                else
                    @handler.map.centerOn { lat: @lat, lng: @lng }
                    @handler.getMap().setZoom $.LOCATIONS_DEFAULT_ZOOM


    class RichMarkerBuilder extends Gmaps.Google.Builders.Marker

        create_marker: ->
            options = _.extend @marker_options(), @rich_marker_options()
            @serviceObject = new RichMarker options

        rich_marker_options: ->
            marker = document.createElement 'div'
            marker.setAttribute 'class', 'marker_container'
            marker.innerHTML = @args.marker
            _.extend @marker_options(), { content: marker }

        create_infowindow: ->
            return null unless _.isString @args.infowindow

            boxText = document.createElement 'div'
            boxText.setAttribute 'class', 'infowindow_container'
            console.log @args
            boxText.innerHTML = @args.infowindow
            @infowindow = new InfoBox(@infobox(boxText))

            @bind_infowindow()

        infobox: (boxText)->
            content: boxText
            pixelOffset: new google.maps.Size(0, 0)
            boxStyle:
                width: '280px'

    $.fn.extend mappy: (option, args...) ->
        @each ->
            $this = $(this)
            data = $this.data('mappy')

            if !data
                $this.data 'mappy', (data = new Mappy(this, option))

            if typeof option == 'string'
                data[option].apply(data, args)

) window.jQuery, window

Then make the data available by doing something like this in your haml

- present @location, LocationPresenter do |p|
     #map{ data: {  markers: [p.marker].to_json, lat: p.latitude, lng: p.longitude } }

ruby on rails - How to do Turbolinks + Gmaps4Rails 2? - Stack Overflow

ruby-on-rails google-maps gmaps4rails turbolinks gmaps4rails2
Rectangle 27 8

There are two common approaches:

Make behavior conditional on the presence of a particular element. For instance, code to run a signup sheet should be prefaced with something like

if $('#signup').length > 0

Make behavior conditional on a class on the body element. You can set the body class using ERB. This is often desirable for stylesheets as well. The code would be something like

if $('body').hasClass 'user'

And if you're interested in CoffeeScript, Trevor is working on a book that looks to be very good: http://pragprog.com/titles/tbcoffee/coffeescript

For solution 2, you can try github.com/tonytonyjan/gistyle which sets conventions for you to use.

How do you limit CoffeeScript (or JavaScript) execution to a particula...

javascript ruby-on-rails coffeescript
Rectangle 27 4

/app/assets/javascripts/user_answers.coffee.js to 
/app/assets/javascripts/user_answers.coffee.js.erb
# Note the level of indentation.
var x = 2;

<% Question.first(2).each do |eq| %>
alert('eq: ' + <%= eq.id %>)
<% end %>

(The indentation level has to match in CoffeeScript, not Ruby.) Enjoy your coffee embedded in rubies.

yet that didn't work anymore for me once I deployed onto heroku. But it did work fine on my machine. Any further ideas?

file.coffee.js.erb
emailRegex = <%= Devise.email_regexp %>

erb in coffee script with rails 3.1 - Stack Overflow

ruby-on-rails erb coffeescript