EL Passion
EL Passion Next Sp. z o.o.EL Passion

Opal on Rails: Replacing CoffeeScript with client-side Ruby

5.01.20174 min
Opal on Rails: Replacing CoffeeScript with client-side Ruby

CoffeeScript is one of the best things that happened to JavaScript. With its clear, easy to read, semicolon-less syntax, it feels almost like Ruby. Almost…

There has been a lot of discussion about isomorphic app development, where both server and client-side parts are written in the same language. One of the most mature and popular attempts to enable isomorphic development in Ruby is Opal.

In this article I’ll show you how easy it is to start writing your client-side scripts in Ruby. Right here, right now, with no excuses! :)

Merging two worlds with opal-rails

First, let’s install opal-rails gem:

$ gem install opal-rails

This gem enables us to generate new Rails application with Opal support (note the --javascript=opal option):

$ rails new opal-on-rails --javascript=opal

When bundle is complete we’re ready to start. Let’s create a controller for manipulating Colors:

$ cd opal-on-rails
$ rails g controller Colors

Then add it to config/routes.rb as a root:

Rails.application.routes.draw do
  root 'colors#index'
end

Now it’s time for some HTML. Create a view app/views/colors/index.erb:

<h1>Hello Opal</h1>
<p>This is simple Opal application</p>

Launch the server and open http://localhost:3000 in your browser.

$ rails s

First encounter

Until now we saw nothing fancy, nothing more than some standard Rails bootstrap app. But take a look at what the controller generator created in app/assets/javascripts/colors_view.js.rb!

class ColorsView
  def initialize(selector = 'body.controller-colors', parent = Element)
    @element = parent.find(selector)
    setup
  end
  attr_reader :element

  def setup
    # Put here the setup for the view behavior
    say_hello_when_a_link_is_clicked
  end

  def say_hello_when_a_link_is_clicked
    all_links.on :click do |event|
      # Use prevent_default to stop default behavior (as you would do in jQuery)
      # event.prevent_default

      puts "Hello! (You just clicked on a link: #{event.current_target.text})"
    end
  end


  private

  def all_links
    @all_links ||= element.find('a')
  end
end

It’s a nice piece of pure Ruby code that logs all clicked links to the browser console. Yup, a real Ruby script that works in a browser!

To see what Opal will generate from this Ruby code, checkout Try Opal online Opal-JS compiler.

To make the script work, we need to edit our template. Open app/views/layouts/application.html.erb, find body tag and edit it:

<body class="controller-<%= controller_name %>">

We also want to initialize ColorsView when the document is loaded. Remember jQuery? rails-opal supports it. At the end of the file just add:

Document.ready? do
  ColorsView.new
end

Looks familiar, right?

The last thing is to add some links to our template, and we’re ready to test the script. Edit app/views/colors/index.erb:

<a href="#">Click me!</a>

Does it work? Of course it does. It’s Ruby :) After clicking on a link we’ll see our JavaScript console flooded with Hello! (You just clicked on a link: Click me!) messages. Perfect.

Digging deeper

Want more? Let’s create some fancier client-side Ruby thing: add links that will change the header color on click.

Add links section to the template:

<section>
  <h3>Change header color to:</h3>
  <ul>
    <li><a href="#" data-color="red">red</a></li>
    <li><a href="#" data-color="green">green</a></li>
    <li><a href="#" data-color="blue">blue</a></li>
  </ul>
</section>

Create another method in ColorsView:

  def change_header_color_when_a_link_is_clicked
    all_links.on :click do |event|
      event.prevent_default
      Element['h1'].css 'color', event.current_target.data('color')
    end
  end

Change setup method:

  def setup
    # Put here the setup for the view behavior
    # say_hello_when_a_link_is_clicked
    change_header_color_when_a_link_is_clicked
  end

And we’re done. Refresh the browser and have fun playing with your isomorphic Ruby app :)

Any color you like, as long as it’s ruby

Opal is a fully featured Ruby implementation, including both corelib and stdlib. You have your much loved blocks, iterators, even method_missing is here! The more I use it, the more I love it. It’s like discovering Ruby again!

The project itself is moving forward pretty fast. The codebase is tested against RubySpec to make Opal as compatible with MRI as possible. There are still some bugs and glitches, but still it’s worth the try. Version 0.8 is around the corner, with working source maps and lots of bug fixes.

What about support for native JavaScript libraries? Well, it’s not that simple like with CoffeeScript. You have to write a wrapper or include pure JavaScript code within backticks (just like executing shell commands in Ruby), although most popular jQuery code works out of the box.

How do you like the idea of writing client-side Ruby? Do you think Opal can replace CoffeeScript? Should it?

<p>Loading...</p>