Mizugumo

Mizugumo is a gem designed to provide Rails with JavaScript and AJAX behavior that is:

See a demo running at:

http://mizugumo-demo.lrdesign.com

Or download the code for the demo at:

https://github.com/LRDesign/mizugumo_demo

Mizugumo uses NinjaScript by Judson Lester to provide unobtrusive JS behaviors. For more info, see:

git@github.com:LRDesign/NinjaScript.git

WARNINGS

In the current (early release) version, Mizugumo and NinjaScript have some limitations. Notably, in this version they will clobber the normal rails.js and prevent its behaviors from working. The installer will copy a jQuery-compatible version of rails.js that you should use instead if you depend on Rails’ default (semi-obtrusive) approaches to AJAX, link_to with :confirm =>‘Are you sure?’ and similar things working.

Features

Mizugumo’s main features are:

Installing

Mizugumo is compatible with Rails >= 3.0.0. We have not tested it with any prior versions of Rails. If you use it with an earlier Rails and it works, let us know!

First, add Mizugumo to your gemfile:

gem 'mizugumo'

Second, install Mizugumo files:

rails generate mizugumo:install

The next step depends on whether you are running Rails 3.0.x or 3.1.x.

Rails 3.0.x

For 3.0.x, mizugumo will assume you are putting most of your application javascript code in public/javascripts/application.js. The installer will have created a Ninja.orders() block in which to place Ninjascript behavior. The last line of this block will be Ninja.go(), and that must remain the last line.

You will need to link to jQuery and NinjaScript in your application layout, and you may include the optional mizugumo.css. (a SASS version is installed to public/stylesheets/sass/mizugumo.sass).

Add these lines to your layout (in ERB):

<%= javascript_include_tag 'jquery-1.6.4.js' %>
<%= javascript_include_tag 'jquery.ninja_script.js' %>
<%= javascript_include_tag 'application.js' %>
<%= stylesheet_link_tag 'mizugumo' %>

If using Haml, add these instead:

= javascript_include_tag 'jquery-1.6.4.js'
= javascript_include_tag 'jquery.ninja_script.js'
= javascript_include_tag 'application.js'
= stylesheet_link_tag 'mizugumo'

NOTE: If you still have javascript_include_tag :defaults, you probably want to remove it. Ninjascript is meant to work with jQuery, and we don’t know what happens if you try to run it side-by-side with Prototype.

Rails 3.1.x

For 3.1.x, mizugumo uses the rails asset packager, so there is less for you to do. ninjascript.js, mizugumo.js, and a file called ninja_go.js are added to your app/assets/javascripts directory, and lines are added to you manifest (app/assets/javascripts/application.js) to ensure that they are loaded in the right order.

Rails’ concept of REST runs headlong into the desire to make a site degrade gracefully. Specifically, the link_to() helper, when passed a method other than ‘get’, outputs a link with a data-method attribute that won’t work when JS is absent. To wit: link_to(‘Delete Item’, @item, :method => ‘delete’) in Rails outputs this:

<a href='/items/1' data-method='delete'>Delete Item</a>

When JS isn’t available, this delete link acts as a show link. This is bad, bad, bad. What’s worse, Rails’ scaffold generator makes these exact links ubiquitous.

When Mizugumo is installed, that same helper instead outputs this:

<form action='/items/1' class="mizugumo_graceful_form">
  <input type='hidden' name='_method' value='delete'>
  <input type='submit' value='Delete Item'>
</form>

This gives the user a button instead of a form … but it works without JS running. Then, to give JS users the behavior the developer intended, Mizugumo appends this to your application.js:

Ninja.behavior({
  '.mizugumo_graceful_form': Ninja.becomesLink
})

This NinjaScript behavior converts that form back into a link. The JS user sees no difference whatsoever, but the link at least works for the non-JS user.

This behavior will work for :method => ‘put’ and :method => ‘post’ as well, and it supports links whose content is an image as well; creating an image submit button in the form rather than a text submit button.

WARNING: This cycle won’t work if your link has complex content with html structure; for example if you write

link_to('some <b>content</b><img src="foo">and text', @item, :method => 'delete' )

Mizugomo will not be able to preserve all that content through the degraded form. However, we think this is a rare case. If you aren’t passing :method to your link_to, mizugumo will ignore it entirely, so you can still create complex GET links.

Scaffold generator

Mizugumo ships with a scaffold generator that builds out-of-the-box AJAX/UJS scaffolds that degrade gracefully in the absence of JavaScript. To use it, add this to config/application.rb:

For ERB views:

config.generators do |g|
  g.scaffold_controller 'mizugumo:scaffold_controller'
  g.template_engine 'mizugumo:erb'
  g.assets 'mizugumo:js_assets'   # Only needed for Rails 3.1, omit for Rails 3.0
end

For Haml views:

config.generators do |g|
  g.scaffold_controller 'mizugumo:scaffold_controller'
  g.template_engine 'mizugumo:haml'
  g.assets 'mizugumo:js_assets'   # Only needed for Rails 3.1, omit for Rails 3.0
end

Run the scaffold generator as you would with any other Rails app. Mizugumo will generate both HTML views (in ERB or HAML), and JavaScript views (action.js.rb) for the actions in each controller, and will generate the NinjaScript code to allow your scaffold to function as an AJAX scaffold when Javascript is available.

In Rails 3.0, the NinjaScript code is injected into public/javascripts/application.js, inside the Ninja.orders() block created by the installer. In Rails 3.1, a new file with the code is created in app/assets/javascripts/<controller_name>.js.

FAQ

What is Ninja.orders()?

NinjaScript’s development is modularized using the RequireJS library. One unfortunate side effect of RequireJS is that modules get loaded asynchronously, and so even if a file is required first, its code is not guaranteed to be available when you load a subsjquent file. So, if you required NinjaScript.js, and then began defining Ninja behaviors like so:

Ninja.behavior({ 'selector': Ninja.someCoolBehavior } )

It is possible that Ninja’s behaviors are not fully loaded, because RequireJS hasn’t finished loading them. Boo! So, Ninja.orders() is defined so to queue up all commands (behaviors and the “go”) command, so that they will get executed as soon as NinjaScript has finished loading.

Contributing to Mizugumo

Reporting Bugs

Use the GitHub issue tracker.

Copyright © 2011 Evan Dorn and Logical Reality Design. See LICENSE.txt for further details.

NinjaScript is copyright © 2011 Judson Lester and Logical Reality Design.

Web Development by Logical Reality Design: LRDesign.com