Reputation: 12605
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()
$('#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
Upvotes: 4
Views: 5656
Reputation: 15306
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')
Upvotes: 0
Reputation: 4144
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.
Upvotes: 2
Reputation: 13332
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
Upvotes: 6