codahale.com٭blog

Coda Hale lives in Berkeley, CA, where he writes about Ruby on Rails, usability, web design and development, and the occasional bit about bicycles.

CRUD Explained

As it’s used on the Rails community, CRUD is when you limit your controller actions to index, new, edit, show, and destroy.

I eagerly await counter-examples.

10 Responses to “CRUD Explained”

  1. Pat Maddox Says:

    That makes sense to me…yet despite having read tons about REST (which isn’t the focus of your post, I realize), I don’t know how to do it in Rails. I made a request that went unnoticed. You seem to have a good understanding though, so maybe you’d want to help out?

  2. Coda Says:

    Pat, you’re asking the right questions, and I don’t know what to tell you. The strict technical answer is that yes, the appropriate HTTP transaction to retrieve all the posts in a particular category is this:

    GET /categories/1

    And that would return something like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <category>
      <name>Announcements</name>
      <id type="integer">1</id>
      <posts>
        <post>
          <id type="integer">1</id>
          <title>Hooah!</title>
          <author_id type="integer">5</author_id>
          <text>etc.</text>
        </post>
      </posts>
    </product-type>

    The code would look something like this:

    class CategoriesController < ApplicationController
      def show
        @category = Category.find(params[:id], :include => [:posts])
        respond_to do |format|
          format.html
          format.xml{ render :xml => @category.to_xml(:include => [:posts]) }
        end
      end
    end

    Or so I gather.

  3. topfunky Says:

    Somewhat off topic, but it seems a little odd that they used respond_to and not respond_to? like the rest of Ruby.

  4. Coda Says:

    Geoffrey–It’s a little odd, but I can understand their reasoning.

    respond_to doesn’t determine whether or not a client can accept, say, XML, and return that as a boolean value. It actually does the responding.

    Also, it would overlap with ActionController::Base#respond_to? which would be bad.

    There’s probably a more elegant syntax for this, though, and I’m sure we’ll see it in a plugin somewhere.

  5. Erik Kastner Says:

    I just wrote a blog post last night with a quick run through of REST on rails. Comments are appreciated.
    On the respond_to question - responds_to seems more natural to me.

  6. Alisdair McDiarmid Says:

    Coda: I think you forgot create and update actions; new and edit should only respond to GET, not POST/PUT.

    In response to Pat’s request, here’s a very simple Rails-REST blog implementation, as you asked for:

    http://randomoracle.com/stuff/RestBlog.tar.gz

    It needs edge Rails (depends on the new RESTful routing from today), and sqlite3. I’ll leave an installation of it online for a while here:

    http://randomoracle.com:3000/

  7. Coda Says:

    Alisdair–No, having multiple actions when one could do the job by paying attention to the HTTP verb isn’t CRUDdy, or so I’m told.

  8. Alisdair McDiarmid Says:

    Coda: Do I detect a hint of cynicism? :-)

    Having multiple *URLs* when one could do the job isn’t RESTful, but the actions don’t map to the URL alone. Pardon me if you know this already, but SimplyRESTful maps URL+verb to an action; this means you can separate your code for preparing the edit form away from the your code for handling the update.

    So map.resources assumes index (GET), new (GET), create (POST), show (GET), edit (GET), update (PUT), and destroy (DELETE). These only map to four URLs: /models, /models/new, /models/:id, and /models/:id;edit.

    Unless I’m much mistaken, that defines what CRUD/REST means to the Rails community, or at least those that agree with DHH on this.

  9. Coda Says:

    Alisdair–Perhaps just a hint. ;-)

    The thing is, though, that most of the time a single edit action makes perfect sense. The updating of a record is always conditional on the verb (or at least it damn well better be), but the need to present an edit UI (if a validation fails, for example) is constantly there.

    For that matter, the updating of a record is usually the same regardless of whether or not the record is new or existing, so that functionality can usually be refactored out into a common action which acts conditionally on the HTTP verb and the presence of an ID parameter.

    Even further, the only difference between GET edit and GET show is the template the retrieved record is displayed with, which means the show functionality can usually be merged into the edit functionality.

    The scaffolds have never struck me as being DRY, so I’m kind of depressed to see their structure being set into canon law. It seems like a lot of hoopla for some very vague and arbitrary design choices. SimplyRESTful strikes me as pretty awesome, though, and I’m happy to see it in core. It’ll make writing web APIs a lot easier.

  10. HostileMonkey Says:

    I think the idea of separating `edit` and `new` from `update` and `create` is that although yes, most of the time they may be performing similar actions, they’re not always doing that in a strict sense. the `edit` action, for example, should only respond to `GET`, not to `PUT`. If it responds to both, it’s difficult to make sure that it’s doing the right things in context.

    I think the RIGHT way to do it, if you want to stay DRY, would be to define a private class method in the controller which performed your combined function, and call it from both `edit` and `update` if you wanted to do that. In that case, refactoring later is dead easy, and you don’t have to mess with the interface.

    I’m viewing the IEN/CSUD convention as being a minimal interface, and any additional DRYness or functionality should be delegated out to private or protected methods. That way anyone picking up your app knows how the routes work without having to worry that changing the way an update works might bork the create action too.