NOTE 3/17/08: I’m aware of the Problems with th Security Token in Rails 2.0.2. I’m gonna deal with that and release a new Version of the Plugin. Right now I’m pretty much occupied with University duties but as soon as time allows it I’m gonna fix this!

                                _______
                               /       \
                               | R.I.P.|
                               |       |
                               |       |
                             -------------

REST in Place is an AJAX Inplace-Editor that talks to RESTful controllers. It requires absolutely no additional server-side code if your controller fulfills the following REST preconditions:

  • It uses the HTTP PUT method to update a record
  • It delivers an object in XML form for requests with “Accept: application/xml” headers

The editor works by PUTting the updated value to the server and GETting the updated record afterwards to display the updated value. That way any authentication methods or otherwise funky workflows in your controllers are used for the inplace-editors requests.

URL: http://svn.varwig.org/rails/plugins/rest_in_place/

Instructions

First, install REST in Place with

script/plugin install http://svn.varwig.org/rails/plugins/rest_in_place/

To use it, include either rest_in_place.js or jquery.rest_in_place.js in your template (after loading the framework’s JavaScript ). rest_in_place.js is the version for the Prototype framework, jquery.rest_in_place.js uses the jQuery framework.

To make a piece of Text inplace-editable, wrap it into an element (a span usually) with class “rest_in_place”. The editor needs 3 pieces of information to work: a URL, an object name and the attribute name. These are provided as follows:

  • put attributes into the element, like this:

    <span class="rest_in_place" url="/users/1" object="user" attribute="name">
      <%= @user.name %>
    </span>
    
  • if any of these attributes is missing, DOM parents of the element are searched for them. That means you can write something like:

    <di v object="user" url="/users/1">
      Name:  <span class="rest_in_place" attribute="name" ><%= @user.name %></span><br/>
      eMail: <span class="rest_in_place" attribute="email"><%= @user.email %></span>
    </div>
    
  • You can completely omit the url, to use the current document’s url. With proper RESTful controllers this should always work, the explicit url-attribute is for cases when you want to edit a resource that is displayed as part of a non-RESTful webpage.

  • Rails provides the dom_id helper that constructs a dom id out of an ActiveRecord for you. So, your HTML page may look like this:

    <di v id="<%= dom_id @user # == "user_1" %>">
      Name:  <span class="rest_in_place" attribute="name" ><%= @user.name %></span><br/>
      eMail: <span class="rest_in_place" attribute="email"><%= @user.email %></span>
    </div>
    

    REST in Place recognizes dom_ids of this form and derives the object parameter from them, so that (with the current documents url used) you really only need to provide the attributes name in most cases.

    !! ——–
    !! Note that a manually defined (in the element or in one of the parents)
    !! object always overrides dom_id recognition.
    !! ——–

Example

Your routes.rb:

map.resources :users

Your app/controllers/users_controller.rb:

class UsersController < ApplicationController
  def show
    @user = User.find params[:id]
    respond_to do |type|
      type.html
      type.xml {render :xml => @user.to_xml}
    end
  end

  def update
    @user = User.find params[:id]
    @user.update_attributes!(params[:user])
    redirect_to @user, :status => :see_other
  end
end

Your app/views/users/show.html.erb:

<html>
<head>
    <%= javascript_include_tag "jquery-1.2.1" , "jquery.rest_in_place" %>
</head>
<body>
    <div id="<%= dom_id @user %>">
      ID: <%= @user.id %><br />
      Name: <span class="rest_in_place" attribute="name"><%= @user.name %></span>
    </div>
</body> 
</html>

Why jQuery?

Why did I write this with jQuery instead of Prototype? (Note: The very first version only had the jQuery version included)

Frankly I never even worked with prototype and have just recently gotten into Javascript using jQuery. jQuery is superior to Protoype and will hopefully replace Prototye someday or at least get integrated into Rails as nicely as Prototype so people can chose which framework they want to use.

Note: Immediately after releasing the initial version I tried porting the plugin to Prototype. I was successful but Prototype really isn’t as much fun to use as jQuery.

Also, REST in Place at this stage is primarily a proof of concept.

Non-Rails

REST in Place was written for Ruby on Rails but is usable with any kind of RESTful web api. Just include the rest_in_place.js in your webpage and follow the instructions.

Participation

I’d love to get comments, bug reports (or better, patches) about REST in Place. I haven’t set up a trac yet, so please use the comments below to contact me.

7 Responses to “REST in Place”

  1. djot Says:

    -
    Hi,

    how about setting up a demo?

    djot

  2. Jan Says:

    Thanks for your interest.

    Unfortunately I don’t have the resources right now to setup a demo.

    You can try it out for yourself very quickly if you just generate a new rails app with a “users” resource, a database table users(id, name) and the controller and view from the readme above. Or, if you already have some RESTful app, just add the span-tag and the include in one of your templates.

  3. Stephen Says:

    Jan,

    Thanks for the contribution. I encourage you to check out some Rails helpers to simplify things. In the head, for example, you could write:

    <%= javascript_include_tag 'jquery-1.2.1', 'rest_in_place' %>

    Rails 2.0 helpers “div_for” (and “content_tag_for”) could help simplify the body, too. It would be nice to have a helper in the plug-in that creates the other tags (you could use a block helper, like “form_for”, to capture the model, and then another helper to yield the spans for that model).

  4. Jan Says:

    Thanks.

    In the most recent revision the javascript and dom_id tags are already used in the README example. I deliberately did not use rails helpers to generate the entire div tag and kept everything simple to not obstruct the main point of this plugin: that no additional server-side code is necessary.

    The idea with the block helper is nice though, I might integrate that.

  5. Nick Says:

    Hi Jan

    I’ve implemented as per your instructions in a Rails 2.0 app using prototype. However the field just says “saving…” after clicking enter and the db isn’t updated.

    My view code looks like this:
    <%=(h @photo.caption) || (h @photo.created_at) %>

    (dom_id is identified in a surrounding div)

    Controller code is:
    def update
    @photo = @event.photos.find(params[:id])

    respond_to do |format|
      if @photo.update_attributes(params[:photo])
        flash[:notice] = ‘Photo was successfully updated.’
        format.html { redirect_to(event_photos_url(@event)) }
        format.xml  { head :ok }
      else
        format.html { render :action => “edit” }
        format.xml  { render :xml => @photo.errors, :status => :unprocessable_entity }
      end
    end
    

    end

    Any ideas?
    thx

  6. Sławek Tuleja Says:

    Hello Jan
    I want to use your plugin but i am getting:
    ActionController::InvalidAuthenticityToken.

    Somewhere in your rest_in_place.js file should olso be authenticity_token parametr.

  7. Jan Says:

    Thanks for the hint!

    I’m gonna deal with that problem and release a new Version of the Plugin soon. Right now I’m pretty much occupied with University duties but as soon as time allows it I’m gonna fix this!

Leave a comment