Yesterday was frustrating; I spent far too long trying to debug some problems in a Rails application I am writing. Rails, and frameworks in general, are supposed to give us improved productivity by hiding the complexity and mechanics of the task at hand. This is great as long as the framework behaves as expected, but invariably causes problems when things go wrong.
belongs_toassociation that was supposed to be populated in a
before_validation_on_createcallback. In my tests I noticed that the linked model was not being instantiated. After much searching, it turns out I had forgotten to create the foreign key field. Unfortunately Rails was silent on this issue and the
belongs_toassociation code seemed to execute quite happily without the field.
has_manyassociations, which I could populate with no problems. When I tried to access the association though, I kept getting
Can’t dup NilClasserrors. This one turned out to be an issue with the generated
collection.buildmethod. As noted in the documentation by the somewhat cryptic Note: This only works if an associated object already exists, not if it‘s nil!, the method fails if the collection is empty (at least that’s what I think it means). Explicitly instantiating the associated model and then adding it to the collection fixed the problem.
In my application I had a model named
Target, which meant that models that associate with
Target, such as my
TargetProfile model, have a
TargetProfilealways returned the instance of
TargetProfile- not quite what is expected. The problem was caused by the fact that
AssociationProxy, used to implement associations between models, has a
targetattribute. The documentation contains another warning Don‘t create associations that have the same name as instance methods of ActiveRecord::Base, but mentions nothing of
AssociationProxy, which isn’t even part of the documented api. I call this broken encapsulation.