52

I have a Rails controller in which I am setting a instance variable -

@user_name = "Some Username"

In my .slim template I am using coffee engine to generate javascript and want to print out the user name from client-sie javascript code -

coffee:
  $(document).ready ->
    name = "#{@user_name}"
    alert name

But this is the javascript that is being generated??

$(document).ready(function() {
    var name;
    name = "" + this.my_name;
    alert(name);
}

How do I access controller instance variables in my CoffeeScript code??

I am tagging this as haml since I am guessing haml will have the same issue when using CoffeeScript .

ylluminate
  • 12,102
  • 17
  • 78
  • 152
kapso
  • 11,703
  • 16
  • 58
  • 76
  • 1
    @Thilo No, he's trying to inject the Ruby variable `@user_name`. Ruby and CoffeeScript use the same string interpolation syntax. – Trevor Burnham Nov 13 '11 at 00:26
  • 1
    I see. BTW, how come the variable name changes from `"#{@user_name}" ` to `this.my_name` ? – Thilo Nov 13 '11 at 00:35
  • Because in coffeescript, @prop gets compiled to this.prop – Cameron Martin Aug 16 '12 at 10:53
  • 1
    http://stackoverflow.com/questions/17560864/performance-implications-of-using-coffescript-filter-inside-haml-templates/19501683#19501683 Similar question/solution – MrYoshiji Oct 23 '13 at 19:58

3 Answers3

94

What's happening is that "#{@user_name}" is being interpreted as CoffeeScript, not as Ruby code that's evaluated and injected into the CoffeeScript source. You're asking, "How do I inject a Ruby variable into my CoffeeScript source?"

The short answer is: Don't do this. The Rails team made an intentional decision not to support embedded CoffeeScript in templates in 3.1, because there's significant performance overhead to having to compile CoffeeScript on every request (as you'd have to do if you allowed arbitrary strings to be injected into the source).

My advice is to serve your Ruby variables separately as pure JavaScript, and then reference those variables from your CoffeeScript, e.g.:

javascript:
  user_name = "#{@user_name}";
coffee:
  $(document).ready ->
    name = user_name
    alert name
Trevor Burnham
  • 76,828
  • 33
  • 160
  • 196
  • thanks for your reply, so basically what you have suggested is ok from performance perspective? – kapso Nov 13 '11 at 12:14
  • 2
    That depends on whether Slim recompiles the CoffeeScript in the template on every request. I'm honestly not sure. You should probably move it to an external file anyway; then it'll only be compiled to JS once, and browsers will cache it. – Trevor Burnham Nov 13 '11 at 13:50
32

I tend to avoid inline javascript at all costs.

A nice way to store variables in your HTML, to be used from your javascript, is to use the HTML5 data-attributes. This is ideal to keep your javascript unobtrusive.

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • That wouldn't be helpful if you're using a JavaScript MVC and want to avoid making multiple HTTP requests to the server. http://backbonejs.org/#FAQ-bootstrap – jackyalcine Jan 29 '14 at 08:19
  • 1
    If you are using javascript MVC, you mostly do ajax requests to get the data, and render the html on the client anyway. But for instance, general config params you can still send once in data attributes in the html/body/container. – nathanvda Jan 29 '14 at 09:08
  • True, true. Sorry if I came off very rash! – jackyalcine Jan 30 '14 at 04:32
2

You could also use:

$(document).ready ->
  name = <%= JSON.generate @user_name %>
  alert name

This is because JSON is a subset of JavaScript.

Makoto
  • 104,088
  • 27
  • 192
  • 230
gene tsai
  • 83
  • 2