I’ve been doing some updating of the codebase of this blog (to add some spam filtering for the comments, among other things, but that’s another post), and I started getting the above error from DataMapper whenever I tried to access the parent post of any comments. Google gives a single result for this error, which is spectacularly unhelpful, so I sort of had to fix it myself :-/.
I started writing this post having done some light investigation into the problem, finding that I was getting property sets instead of a single property deep inside datamapper’s validation code, and assuming I’d found a bug in there or similar (particularly since all the relevant code has been rewritten from scratch in their current trunk), or at least something interesting to talk about. The DataMapper internals seemed to suggest you should only PropertySets if you had more than one property anyway, and the debug output definitely only showed one contained value ([…] is actually ‘[#<DataMapper::Property::Serial @model=Comment @name=:id>]’, for those interested), so I went looking for reasons why DataMapper would be confused and building sets instead of single items like it should’ve.
Unfortunately, although this is sort of dubious behaviour on datamapper’s part, it’s actually dubious behaviour in response to terrible input: it’s entirely my fault and quite foolish, but this post remains nonetheless, in case somebody else is equally foolish (such as the guy in the other google result). The problem here is really just because of minor typo, and the real problem is just the bad error message.
Anyway, there wasn’t any obvious immediate reason for the propertyset so I quickly decided everything was going to go quicker if I stripped the relevant bits of my model down to a minimal repro, which is this:
property :id, Serial
has n, :comments
property :id, Serial
belongs_to :post, key => true
Don’t know about you, but that looked pretty good to me. Unfortunately, some very careful inspection shows it’s definitely not. In fact, ‘key’ should ‘:key’, because while you can reference your column types directly, you need to actually use symbols for properties, like key, or you’re saying something entirely different! Presumably it looks up ‘key’, builds a set of properties to store the two of these (post and key) and then gets highly confused when no ‘key’ exists, leading to the validation error. I’m assuming this blindly, because adding the colon totally fixes it, and I’d rather blather at the internet than walk through every line of DataMapper for nothing; me being clearly wrong is quite enough explanation for now.
Summary: if you have this error, you’ve probably left a colon off a property in your model. You should fix that.