23

I have views in my application that reference my application.js file which contains functions I use throughout my application.

I just installed the Rails 3.1 release candidate after having used the edge version of 3.1. Until I installed the RC I wasn't having any problems but now I'm getting this error:

ReferenceError: Can't find variable: indicator_tag

indicator_tag is a function I defined in application.js. The only difference I notice in the javascript file is that now all my functions are wrapped in:

(function() { ... }).call(this);

I understand this is for variable scoping? But could it be preventing my pages from using those variables? And before anyone asks, I've made sure the javascript paths are correct in my include tags.

tanman
  • 1,379
  • 1
  • 10
  • 19

2 Answers2

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 ||= {}

This will ensure that there's a global named Application present at all times.

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
  • 212,659
  • 41
  • 396
  • 397
  • 9
    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: https://github.com/rails/rails/issues/1125 – Trevor Burnham May 22 '11 at 21:36
  • I would give you 10 ^s if I could for that answer. Thanks so much. – barelyknown May 18 '12 at 13:07
13

Dogbert's solution is a great way to go if you have a very sophisticated JS back-end. However, there's a much simpler solution if you only have a handful of functions you're working with. Just add them directly to the window object, like this:

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

Then you can use your functions from anywhere without having to wrap them up in another object.

Travis
  • 735
  • 7
  • 12
  • 1
    What's so bad about wrapping them in another object? If you want to avoid typing "Application" call it "App". The context is often really useful anyway when you're just reading the code… – Graham Ashton Feb 29 '12 at 21:36
  • And, I would add than this "window." is the same than "@", isn't it? – Albert Català Feb 04 '14 at 15:25