zhubert

a programming blog

Batman.js and Rails Part 2, Batman Install

So, Rails is ready, let’s get Batman talking. It turns out to be really easy.

First let’s run the generator that comes with batman-rails:

1
$ rails g batman:install

I’m not a fan of having things directly under javascripts so I moved the created directory structure so things are like: (copying a fresh Batman 0.9.0 install into place under lib):

1
2
3
4
5
app/assets/javascripts
--> batman/
----> [controllers/,helpers/,models/,views/]
--> lib/
----> [batman.js,batman.jquery.js,batman.rails.js]

Taking a peek at your application.js.coffee (yes I changed the extension) you see a very simple loading of the Batman app:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#= require jquery
#= require jquery_ujs
#= require bootstrap

# Batman.js and its adapters
#= require ./lib/batman.js
#= require ./lib/batman.jquery.js
#= require ./lib/batman.rails.js
#= require ./lib/batman.paginator.js

#= require batman_rails_demo

#= require_tree ./batman/models
#= require_tree ./batman/controllers
#= require_tree ./batman/helpers

#= require_tree .
# Run the Batman app
$(document).ready ->
  BatmanRailsDemo.run()

The astute will notice I added #= bootstrap and that Batman has provisions for Rails directly! Woo hoo, that’s encouraging.

So now let’s take a peek at the main Batman Application file:

app/assets/javascripts/batman_rails_demo.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
window.BatmanRailsDemo = class BatmanRailsDemo extends Batman.App

  @title = "Batman Rails Demo"

  # 0.8.0 changed to this syntax
  Batman.ViewStore.prefix = 'assets/batman/views'

  @navLinks: [
    {href: "/#!/posts/", controller: "posts", text: "Posts"},
  ]

  # routing...
  @resources 'posts'
  @root 'posts'

  # here and below is automatically generated
  @on 'run', ->
    console?.log "Running ...."

  @on 'ready', ->
    console?.log "BatmanRailsDemo ready for use."

  # flash is a simple object
  @flash: Batman()

  # when you set an message, it auto-expires
  @flash.accessor
    get: (key) -> @[key]
    set: (key, value) ->
      @[key] = value
      if value isnt ''
        setTimeout =>
          @set(key, '')
        , 2000
      value

  @flashSuccess: (message) -> @set 'flash.success', message
  @flashError: (message) ->  @set 'flash.error', message

Most of that is boilerplate, but we can see that I added some Nav bits and that routing takes TWO LINES! It even looks like a Coffee-ized Rails. Neato. The ViewStore bit is really important. If you get errors from Batman saying it can’t find your views, it is either that line or missing asset pipeline gems.

The model:

app/assets/javascripts/batman/models/post.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
class BatmanRailsDemo.Post extends Batman.Model
  @resourceName: 'post'
  @storageKey: 'posts'

  @persist Batman.RailsStorage

  # fields
  @encode "title", "content"

  # validations
  @validate "title", presence: true
  @validate "content", presence: true

RailsStorage! It happily passes serverside validation errors to our client, that’s cool. Validation syntax is terse as are field definitions.

The controller:

app/assets/javascripts/batman/controllers/posts_controller.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class BatmanRailsDemo.PostsController extends Batman.Controller
  routingKey: 'posts'

  index: (params) ->
    BatmanRailsDemo.Post.load (err,results) =>
      @set 'posts', results

  show: (params) ->
    @set 'post', BatmanRailsDemo.Post.find parseInt(params.id, 10), (err) ->
      throw err if err

    @render source: 'posts/show'

  new: (params) ->
    @set 'post', new BatmanRailsDemo.Post()
    @form = @render()

  create: (params) ->
    @get('post').save (err) =>
      $('#new_post').attr('disabled', false)

      if err
        throw err unless err instanceof Batman.ErrorsSet
      else
        BatmanRailsDemo.flashSuccess "#{@get('post.title')} created successfully!"
        @redirect '/posts'

  edit: (params) ->
    @set 'post', BatmanRailsDemo.Post.find parseInt(params.id, 10), (err) ->
      throw err if err
    @form = @render()

  update: (params) ->
    @get('post').save (err) =>
      $('#edit_post').attr('disabled', false)

      if err
        throw err unless err instanceof Batman.ErrorsSet
      else
        BatmanRailsDemo.flashSuccess "#{@get('post.title')} updated successfully!"
        @redirect '/posts'

  # not routable, an event
  destroy: ->
    @get('post').destroy (err) =>
      if err
        throw err unless err instanceof Batman.ErrorsSet
      else
        BatmanRailsDemo.flashSuccess "Removed successfully!"
        @redirect '/posts'

That is structured exactly like a resourceful controller in Rails (although destroy isn’t routable). Convenient. A Rails developer should look at this as the MVC they already know.

So good so far. Next time…views.

Posted by Zack Hubert batmanjs, rails

Tweet

« Batman.js and Rails Part 1, Server Side Batman.js and Rails Part 3, Views »

Comments

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.