Rails and REST: ActiveResource doesn't play nice with domain-driven resource identifiers

An update from my post from a few days ago where I talk about REST and domain identifiers. This is the entirety of the code from ActiveResource::Base#save:

def save
  new? ? create : update
end

Here’s the punchline:

def new?
  id.nil?
end

ActiveResource doesn’t document it, but you can override the primary key that it uses to communicate with your backend system (self.primary_key = :username) and indeed this is the most effective way I know of ensuring that it performs deletes and updates with the appropriate key. The trouble is that if you attempt to create a resource remotely and pre-populate the username (which you’d want to be able to do; it is, after all, a domain identifier) ActiveResource chokes and tries to update the remote resource instead of saving it.

To put it another way: ActiveResource thinks that if your resource has an ID it’s not new. It cannot separate the concepts of auto-increment database-generated ID and resource identifier.

The correct way to solve this problem is to flag any resources retrieved from a remote system as “not new” and consider any other created resources as new. Until that’s fixed I recommend using a conditional approach in which your controller checks incoming IDs and finds on the appropriate column based on whether or not the ID looks like a resource identifier or a database integer. More on that next post.

This is part of a series of posts on Rails and REST. Read the rest.

Make Lotus 8.5 Pretty After Upgrading

The difference between commentary and conversation