Monday, August 27, 2007

ActiveResource Won't Always Play Nice With Form Handlers

One thing to watch out for developing a Rails app with ActiveResource is that all the form handlers on the front end assume ActiveRecord objects, and the mismatch there can seriously kill your productivity. If you want a return to the past - or an idea of what PHP and Java developers still tolerate every day - try to use standard ActionPack form handlers with ActiveResource. form_for is particularly painful, and date_select nearly has to be done entirely by hand. Validations, as Chad Fowler noted at Rails Edge, are also pretty painful.

The problem, basically, is that the attr_accessor-like methods you can expect on an ActiveRecord object won't be there for an ActiveResource object until HTTP response time (I think), while they're there on ActiveRecord objects from the moment you attempt to use them. Currently I'm dealing with this with a lot of painful, manual hacking, but the correct response is probably a method_missing on ActiveResource::Base that looks like the one in ActiveRecord.

An even better approach might be to make both ActiveRecord and ActiveResource subclasses of some object which represents an active record with no assumptions about its data store. The flaw here, of course, is that using ActiveResource as if it were ActiveRecord is not generally recommended. There's at least one good reason to do it anyway, though. (That'll be the subject of an upcoming post, I think.)

4 comments:

  1. "An even better approach might be to make both ActiveRecord and ActiveResource subclasses of some object which represents an active record with no assumptions about its data store"

    Why subclass? Why not just put a Facade pattern in front of the two?

    This is what I was referring to in my earlier comment).

    ReplyDelete
  2. Ack ... hit "publish" too soon.

    Maybe I'm missing something obvious, but couldn't you just have an ActiveRecordOrResource class that will pass through things like .find(:id) appropriately?

    ReplyDelete
  3. It would be cool if REST controllers had an action that provided some representation of their schema, maybe relax-ng or whatever the XML schema definition de jour is. ActiveResource could request that schema so it knew what to expect and could construct the attribute methods you need.

    This would be similar to the way ActiveRecord executes "SHOW FIELDS FROM table" to get the list of columns that belong to the table.

    ReplyDelete
  4. @joe - actually that's what I was thinking of. my design patterns lingo eluded me, but that's what I meant.

    @sean - exactly. ActiveResource does something very similar to ActiveRecord's dynamic method assignment, but it happens at the wrong time. if you use a date_select form handler in an ActiveResource create method, the form handler can't get the date object initially, and the code falls apart on the absence of that date method. But if you stub it in with attr_accessor, the #find code which is supposed to generate it won't generate it. You're forced to patch the method onto the individual object, and only when !request.post?. It gets messy. If the process were cleaner and simpler, like Rails migrations or auto-generated schemas (technically schemae), using ActiveResource would be so much easier.

    ReplyDelete

Note: Only a member of this blog may post a comment.