Opalを使ったRailsアプリケーションを作った時に自動生成されるサンプルコードを動かしてみる

# Opalとは
[Opal](http://opalrb.org/)は、Ruby => JavaScriptのコンパイラです。
HTML内に埋め込んだRubyのコードを走らせるパーサーもあり、

```html+erb
<script type="text/ruby">
  puts 'hello'
</script>
```

みたいな形で試すことも簡単に出来ます。

[opal-rails](https://github.com/opal/opal-rails)を使えば、JavaScriptのアセットを全てRubyで書くことが出来るようになるので、よりPure Rubyなプロジェクトを作れます。
こちらのリポジトリの説明には**「Bringing Ruby to Rails」**なんて書かれていたりして、知らない人が見たら何がなんだかわからないだろうなと思われます…（笑）

## Opalを使ったRailsアプリケーションを作ってみる
rails new で Opalを指定すると、必要なgemが入った状態でプロジェクトが生成されます。

```bash
rails new <app-name> --javascript=opal
```

続いて、下記のいくつかの設定を行う必要があります。

* `config/application.rb` へ指定されたパラメータの追加
* `app/assets/javascripts/application.js` を `application.js.rb` へ差し替え

詳細は[opal-rails](https://github.com/opal/opal-rails)のページを参照ください。

## コントローラを生成する
ここでは、仮にコントローラ名を`examples`として生成します。

```
rails generate controller examples
```

コントローラを作ると、`assets/javascripts`内に、`examples_view.js.rb`が生成されます。
このファイルは必ず**複数形で生成される**ようなので、複数形でコントローラ名を指定した方がサンプルを動かす分には楽そうです。

## 自動生成されたファイルを見てみる
下記のファイルが生成されました。

```rb:app/assets/javascripts/examples_view.js.rb
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use Opal in this file: http://opalrb.org/
#
#
# Here's an example view class for your controller:
#
class ExamplesView
  def initialize(selector = 'body.controller-examples', 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
```

内容としては、

* `body.controller-examples`を取ってくる
* body内の`<a>`要素を全部取ってくる
* `<a>`要素をクリックしたら、コンソールに"Hello!"と表示する

と言った感じのことを行うclassのようです。

`event.prevent_default`のコメントを外すとリンククリック時の画面遷移が無くなりますが、今回のサンプルではリンク先を#にするので、外しても外さなくてもどっちでも良いです。

## もろもろ準備する
1.ビューを用意する

```rb:app/views/examples/index.html.erb
<%= link_to 'Click me!', '#' %>
```

2.コントローラにアクションを追加する

```rb:app/controllers/examples_controller.rb
class ExamplesController < ApplicationController
  def index
  end
end
```

3.ルートを通す

```rb:config/routes.rb
Rails.application.routes.draw do
  root 'examples#index'
end
```

4.bodyのclassにコントローラ名が入るようにする

```html+erb:app/views/layouts/application.html.erb
<body class="<%= "controller-#{controller_name}" %>">
  <%= yield %>
</body>
```

## ExamplesViewのインスタンスを作る
もう一度、先ほど自動生成された`examples_view.js.rb`を見てみると、classの宣言のみでインスタンスを作っていないので、ページの読み込み完了時にインスタンス生成のコードが発火するようにします。

```rb:app/assets/javascripts/examples_view.js.rb
Document.ready? do
  ExamplesView.new
end
```

こちらの`Document.ready?`は、大体お察しだと思いますが、jQueryの`$(document).ready`です。
opal-jqueryはopal_ujsに含まれているので、このファイル中でrequireする必要は無いようです。

## 動く
<img width="355" alt="スクリーンショット 2016-07-10 3.16.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/45427/a98b3553-ba24-ded4-c726-7d6abe8b6346.png">
こんな感じで、Rubyで書いたclassが普通にWebページの中で動いています。
何だか不思議な感じがしますね…。

## 実用性とか
もうちょっと使ってみて考えてみますが、
DOM操作は基本opal-jqueryで行うことになりそうなので、普通のjQueryを使い慣れていない身としては、結局jQueryのAPIドキュメント読む所からスタートなのか…と若干重い気分になります。

他のJSラッパーについては、[Awesome Opal](https://github.com/fazibear/awesome-opal)眺めてみたら色々見付かりそうです。
[Reactrb](http://reactrb.org/)とかあったりするようなので、ここから試してみようと思います。
[Volt](https://github.com/voltrb/volt)と言う、表・裏共にRubyで書けることを売りにしているフレームワークもあって、こちら人気っぽいので試してみたいです。