If there is a combinatorial way to bring aspects of a framework together in a breaking edge case, I will find that way and take that step. It’s a destiny one follows gladly; an instinct useful in defining the boundaries of an application’s logical complexities as they accumulate on the brain like bit patterns. It makes you wade through limitations, leading to unexpectedly serviceable workarounds.
The problem for me, at least, is that I can’t turn the compulsion off. It sits right below my consciousness, urging the brain, when given a system, to seize upon the most elegant paradox it detects for solving the problem at hand. Take, for example, polymorphic belongs_to associations with accepts_nested_attributes_for in Rails. Any two of these keywords in combination will turn up tales in the SERPs of bewilderment and errors, but the effort to solve a data modeling problem brought these three elements together in a perfect storm that would punish me for my inspiration.
So I’ve one model, which then belongs_to another, polymorphic, model. The belongs_to model was the workhorse of the pair, and therefore needed to accepts_nested_attributes_for in order to initialize its counterpart as required.
class BelongsToModel < ActiveRecord::Base belongs_to :polymorph_model, :polymorphic =>true accepts_nested_attributes_for :polymorph_model end
Unfortunately, what appears to happen when one puts this design into practice is that a NoMethodError is thrown whenever the belongs_to model receives the nested attributes hash, e.g.
params = {
:name => “blah”,
:parent_type => “polymorph_obj_class”,
:polymorph_model_attributes => {
:info => “blah”,
:details => “blah”
}
}
@belongsToModel = BelongsToModel.new(params)
In the example, polymorph_model_attributes is constructed with the attributes “info” and “details” because I personally have the domain knowledge to know that those attributes belong to the polymorph model and should be provided. To process nested attributes, however, Rails needs to know this also so it can use that knowledge to add an appropriate build method (called something like ‘build_polymorph_model ‘) to the belongs_to model, and initialize the nested object whenever the belongs_to model is initialized.
The paradox arises because Rails cannot dynamically create a “build_polymorph_model” method without first knowing the class of the polymorph. Even passing in a parent_type or equivalent attribute will not provide the model with the foreknowledge it needs to build this helper method.
Any alteration to my data model would be enough to escape the conflict, but this uncomfortable relationship with belongs_to and the need to instantiate my objects from the direction of the belongs_to model came about because it really does best represent the schema behind the scenes, and so I was loathe to surrender it to the apparent constraints.
The solution was as simple as possible. I took a literalist approach, and went ahead and defined the build_polymorph_model explicitly myself, adding in the appropriate logic to initialize any one of the several possible polymorphic models that could be associated.
class BelongsToModel < ActiveRecord::Base
belongs_to :polymorph_model, :polymorphic =>true
accepts_nested_attributes_for :polymorph_model
def build_polymorph_model(params)
# build any supported polymorphic relationships here
end
end
