开发者

Rails/Javascript: How to inject rails variables into (very) simple javascript

I want to write up a very simple javascript calculator in rails which multiplies the quantity of an input field by a number stored in a rails variable (@item.base_price)

So, on the javascript/coffeescript side of things, it's crudely this:

# app/assets/javascript/items.js.coffee
$ -> 
  $('#item_quantity').change ->
    quantity_val = $(this).val()
    $开发者_如何学Python('#total_amount').html(quantity_val * <%= I_WANT_@ITEM.BASE_PRICE_HERE %>)

I'm aware of how I can do this via an ajax call on each change() call, but I figure there has to be an elegant, hopefully unobtrusive rails way which doesn't hit the server each time.

Any suggestions very appreciated


If you are using rails 3.1 you can take advantage of the assets pipeline to do some pre-processing on the javascript files before you serve them up. To do this just change the file extension from:

items.js.coffee

to

items.js.coffee.erb

then you can add ruby to your javascript just like in your view with <%= %> tags. The only gotcha you might run into, is that your items.js file will be served to every request to any of your app's controller methods. So its best to write a helper method that will return the value only if the instance variable is initialized

For example in items_helper.rb

def item_price
    if @item
        @item.base_price
    else
        0
    end
end

EDIT: more about assets pipeline here:

http://guides.rubyonrails.org/asset_pipeline.html


Although... if you serve up the Javascript files as static assets, this might not be optimal. I typically put a script tag in the head section of the HTML with the variable. That way, the JS doesn't have to be rebuild and the browser cache for it invalidated. E.g.:

<head>
  <script type="text/javascript">
    var myGlobalVariable = <%= @global_js_variable %>;
  </script>
</head>

While this stinks for keeping things in their separate namespaces, it does reduce the overhead of shipping new Javascript files to the client.

Just a thought.


Using the asset pipeline to process your CoffeeScript files with ERB on a per-request basis may be fine for development, but it will be a bottleneck in production.

In production, I use a global variable or a specific property of a global variable to reduce pollution.

At the bottom of the page's ERB view:

<script>
  //<![CDATA[
    window.MyApp = window.MyApp || {};
    window.MyApp.itemBasePrice = <%=j @item.base_price.to_json.html_safe %>;
  //]]>
</script>

Always put scripts at the bottom (and stylesheets at the top) of your page since it leads to faster perceived page load times.

I highly recommend reading this article on How to securely bootstrap JSON in a Rails view. The latest version of Rails at the time of this writing is vulnerable to XSS attacks when bootstrapping JSON in this way. If you just have a simple number, it may not be an issue. But I find that after people see your code working, they tend to simply copy/paste it to more complicated situations without thinking about the consequences.

Alternatively, if your data has a natural container, you can embed it in a data attribute.

<div id="item" data-base-price="<%=j @item.base_price.to_json.html_safe %>"></div>

Accessing it in your CoffeeScript:

console.log $('#item').data('basePrice')
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜