rails-api/active_model_serializers — pull request #658 by kbullaughey (2014-09-20 20:31:30+00:00)
Title: gracefully handling name collisions with ActiveModel::Serializer methods

I posed issue #657 about an issue I was having where my model property, `root`, collided with `ActiveModel::Serializer#root`. The problem lay in how Serializer#attributes only defines an accessor method if one doesn't already exist.

This is tricky because a major feature of AMS is that one can define methods in descendent classes and when registering an attribute with this name, it should call that method. But how does one know which methods are on the serializer as part of the model's serialization design scheme, and which ones are part of ActiveModel::Serializer itself.

In my proposed fix, I register accessor methods prefixed with `_accessor_for_` and then call these when it seems appropriate, namely if the serializer doesn't have a method by the given name or when it does, but that method was defined on ActiveModel::Serializer itself (using `method(name).owner == ActiveModel::Serializer`)

This works, but feels very hackish. It's also fragile. I'm assuming I only care about collisions that are defined on `ActiveModel::Serializer` and not modules included therein or in ancestors, etc.

I'm sure there's a more robust way to do this.

In particular, I liked the idea of specifying a name separate from the method name, like I mentioned in #657:

attribute :original_root, key: :root
def original_root
object.root
end

But I couldn't find the implementation of `attribute` and couldn't see any easy way to implement this. Plus it seemed like conflicts should be handled gracefully from the start.

I'm sure there is a good, elegant solution out there, I just couldn't think of it without substantial refactoring (which appears to be going on anyway for 0.10.0).