#297 Running JavaScript in Ruby pro
Sometimes logic needs to be shared between the server-side (Ruby) and the client-side (JavaScript). Here I show how to run JavaScript directly in Ruby through ExecJS and therubyracer.
- Download:
- source codeProject Files in Zip (110 KB)
- mp4Full Size H.264 Video (36 MB)
- m4vSmaller H.264 Video (17.1 MB)
- webmFull Size VP8 Video (18.9 MB)
- ogvFull Size Theora Video (40.2 MB)
Resources
models/member.rb
class Member < ActiveRecord::Base validate :check_membership_number def check_membership_number source = File.read(Rails.root.join("app/assets/javascripts/membership_number.js")) context = ExecJS.compile(source) unless context.call("isValidMembershipNumber", membership_number) errors.add :membership_number, "is an invalid number" end end end
Gemfile
gem 'therubyracer', require: 'v8'
rails c
c = V8::Context.new c.eval('1 + 2') c[:num] = 3 c.eval('num * num') c.eval('math = {square: function(n) { return n*n }}') c[:math].square(5) c[:square] = lambda { |n| n*n } c.eval('square(4)')
products/index.html.erb
<%= render "product", :mustache => product.for_mustache %>
models/product.rb
def for_mustache Thread.current[:product_v8] ||= V8::Context.new.tap do |context| coffee = File.read(Rails.root.join("app/assets/javascripts/product.js.coffee")) javascript = CoffeeScript.compile(coffee) context.eval(javascript) end Thread.current[:product_v8].eval("new Product(#{to_json})") end
products.js.coffee
product = new Product(product_attributes)
product.js.coffee
class Product
constructor: (@attributes) ->
id: -> @attributes.id
name: -> @attributes.name
price: ->
digits = String(Math.round(@attributes.price * 100)).split("").reverse()
formatted = [digits.shift(), digits.shift(), "."]
for digit, index in digits
formatted.push(digit)
if (index+1) % 3 == 0 && index+1 < digits.length
formatted.push(",")
"$" + formatted.reverse().join("")
released_at: ->
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
date = new Date(@attributes.released_at)
day = date.getDate()
month = months[date.getMonth()]
year = date.getFullYear()
"#{month} #{day}, #{year}"
@Product = Product

