LoginSignup
23
23

More than 5 years have passed since last update.

Mithril.jsをRailsで始める

Last updated at Posted at 2015-08-14

Mithril は名前を聞いたことがある程度で、特に触ってみる予定はなかったのですが、Shibu's Diary: 世界最速でMithril本をリリースした話 を見て俄然興味が湧いたので、早速、黒ムツ本 を購入して読みました。
コンパクトで大変読みやすかったです。オススメ。コードもMITライセンスで公開 されていて嬉しい。

あえてRailsで

本を読んでなんとなく理解できたところで、次は実際に触ってみるフェーズ。
今後いろいろといじっていくにあたり、サーバサイドは使い慣れているRailsでやりたい。
ということで、まずはTodoのサンプルをRails化してみました。

全コードはこちらにあります。
https://github.com/tnantoka/my-mithril

やったこと

Mithrilを入れる

mrsweaters/mithril-rails は古かっ1し、今回はMSX を使う予定もなかったので、rails-assets で入れました。

Gemfile
source 'https://rails-assets.org' do
  gem 'rails-assets-mithril'
end
$ bundle
app/assets/javascripts/application.js
//= require mithril

コンポーネントを書く

app/assets/javascripts/components/todo.coffeeに置きました。

モデル

class Todo
  constructor: (data = {}) ->
    @description = m.prop(data.description || '')
    @done = m.prop(false)

  @list: ->
    m.request(method: 'GET', url: '/todos', type: Todo, initialValue: [])
  @save: (list) -> 
    data =
      todos: list.filter (t) -> !t.done()
    MyMithril.request(method: 'POST', url: '/todos', data: data)

MyMithril.requestcsrf-tokenを追加してm.requestを呼ぶ自作関数です。https://github.com/tnantoka/my-mithril/blob/master/app/assets/javascripts/my-mithril.coffee

mithril-rails使えば勝手にやってくれる?(未確認)

ビューモデル

Enterキーで保存できるようにしています。

vm =
  init: ->
    vm.list = Todo.list()
    vm.description = m.prop('')
    vm.entered = m.prop(false)
  add: ->
    if vm.description().length
      todo = new Todo(description: vm.description())
      vm.list().push(todo)
      vm.description('')
      Todo.save(vm.list())
  toggle: (value) ->
    @done(value)
    Todo.save(vm.list())
  onkeyup: (value) ->
    vm.description(value) unless vm.entered()
    vm.entered(false)
  onkeypress: (e) ->
    if e.keyCode == 13
      vm.entered(true)
      vm.add()
    else
      m.redraw.strategy('none')

コントローラー

controller = ->
  vm.init()

ビュー

onchangeはfocusがある間は発生しない(忘れててちょっとハマった)ので、onkeyupで入力中のキーワードをvm.descriptionに設定しています。

view = ->
  m 'div', [
    m '.row', [
      m '.col-sm-4', [
        m '.input-group', [
          m 'input.form-control', {
            value: vm.description()
            onkeyup: m.withAttr('value', vm.onkeyup)
            onkeypress: vm.onkeypress
          }
          m 'span.input-group-btn', m 'button.btn.btn-primary', onclick: vm.add, 'Add'
        ]
      ]
    ]
    m 'div', vm.list().map (t) ->
      textDecoraton = if t.done() then 'line-through' else 'none'
      m '.checkbox', [
        m 'label', [  
          m 'input[type=checkbox]', onclick: m.withAttr('checked', vm.toggle.bind(t)), value: t.done()
          m 'span', { style: { textDecoration: textDecoraton } }, t.description()
        ]
      ]
  ]

コンポーネントを呼び出す

手抜きでViewから呼んでます。

app/views/welcome/todo.html.slim
javascript:
  m.mount($('#app').get(0), components.todo.component);

サーバーサイドを実装する

createでは受け取ったデータをsessionに突っ込んで、indexではそれをそのまま返しています。

app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def index
    render json: session[:todos].to_a
  end

  def create
    session[:todos] = params[:todos]
    render nothing: true
  end
end

テストを書く

それなりに長いので割愛。
https://github.com/tnantoka/my-mithril/blob/master/spec/javascripts/todo_spec.coffee にあります。

実行には、Teaspoon を使いました。README通りやればCoverageもちゃんと取れてよかったです。
Sinon.JSのserver.respondImmediately = trueがなぜか効かなかった(?)り、npm module使えるの?とかまだわかってないところだらけですが。

動いた!

http://my-mithril.bornneet.com/ で動いています。

tweet-boxの方はReact.js Introduction For People Who Know Just Enough jQuery To Get By · React for Designers の劣化コピーです。(Rails関係ない)

感想

まだ触り始めたばかりですが、vue.js ぐらい手軽に利用できて、しかもrouter2 も付いてきて、設計指針も示してくれる(これは本が親切なのもありますが)ので、片手間フロントエンダーには大変ありがたいと思いました。

だいぶ慣れてきたので、次は何か大きめのものを作ってみる予定。


  1. 僕がMithrilの勉強を始めた先週末時点では数ヶ月放置されてた。今はちゃんと最新版にアップデートされてるみたい。 

  2. ラウターと読む癖を付けよう! 

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23