Unobtrusive Javascript Form Extensions for Rails 3

Edifice-widgets is a companion gem to edifice which improves and simplifies your experience writing forms for rails.

Note that it does not depend on edifice, although it complements it well.

Installation

To install, simply add to your Gemfile:

ruby gem 'edifice-forms'

To include the javascript, add to your application.js:

js /* *= require edifice-forms */

Extending remote forms to handle errors

Rails 3 includes the excellent Unobtrusive JS, which allows us to define remote forms unobtrusively:

```html

``` This will result in the form submitting via AJAX, however there is no support for errors in the form. This is surprising as the convention for rails form errors is clearly defined; return a HTML status 422 (`:unprocessible_entity`). In fact this is what the `responds_with` responder will do (for non-AJAX requests): ```ruby # Super-lean Rails controllers do it for me class UsersController def update respond_with @user = User.update(params[:user]) end end ``` edifice-forms extends this convention to AJAX requests. Firstly, we augment rails to respond with a 422 on invalid AJAX updates. Secondly, we add a `data-form` attribute: ```erb <%= form_for @user, :remote => true, :html => => 'show_errors' do |f| %> ``` Now, when your users controller returns an error + an updated form with the errors highlighted, we'll automatically replace the form with the 'errored' version. Not a single line of Javascript required for such a common behaviour! rails_form.js ------------- What about if your form returns data in JSON? We've got you covered. In order for remote JSON forms to show errors, we've written a small jQuery plugin: `rails_form.js`. It is written to conform to the conventions laid down by actionpack. For instance, if you have, in your view: ```html </input>
``` You can call: ```js $('form').rails_form('add_error', 'user[name]', 'needs a surname'); ``` Which will result in: ```html
needs a surname
</input>
``` The error can be removed with: ```js $('form').rails_form('clear_error', 'user[name]'); ``` We've also added a convention that rails seemed to leave out, if you prefer your errors to be co-located: ```erb <%= render_errors(f) > ``` Which will output something like: ```html
  • Name needs a surname
``` Forms with `show_errors` set will detect such a structure and update it on AJAX errors. Use at your discretion. FormModel --------- The final piece of the puzzle is perhaps the most useful. Suppose you have a form on your site which isn't backed by a model. A good example is a feedback form. The feedback 'model' doesn't need to persist, it simply needs to send an email when it successfully saves; but we would still like to have all the ActiveModel goodness (validations, callbacks, etc) of a real ActiveRecord model. Enter the FormModel: ```ruby class Feedback < Edifice::Forms::FormModel attr_accessor :message attr_accessor :email # some simple validators validates :email, :presence => true, :format => => /^.+@.+\..+$/ validates :message, :presence => true after_save :deliver_feedback # if validations pass and we successfully save, go ahead and deliver the # feedback email to us, so we can read it. def deliver_feedback SelfMailer.feedback(self).deliver end end ``` Looks a lot like a ActiveRecord model, doesn't it? We get to write our controllers in the same super skinny way: ```ruby class FeedbacksController < ApplicationController def new respond_with @feedback = Feedback.new end def create respond_with @feedback = Feedback.create params[:feedback] end end ``` Don't worry, we can use the `@feedback` in our views just as we would with a real model: ```erb <%= form_for @feedback, :remote => true, :html => => 'show_errors' do |f| %> <%= f.label :message, 'Your Feedback' %> <%= f.error_message_on :message %> <%= f.text_area :message, :placeholder => 'How can we help?' %> <% end %> ``` Simple, huh? License ------- [Edifice](http://edifice-rails.com) is crafted by [Percolate Studio](http://percolatestudio.com) and released under the [MIT license](www.opensource.org/licenses/MIT)