remiprev/her — pull request #199 by vic (2013-11-10 05:31:51+00:00)
Title: Forward *almost* all methods to the fetched object.

It was somewhat weird that `her` association methods returned an object that in some cases masked some of
the methods defined by Object / Kernel instead of delegating them to the fetched value.

Suppose you had a relation where a `User` has one `Role`. After fetching the `user` object along with
it's associated role, if you did called `class` on it

```ruby
user.role.class # => Her::Associations::HasOneAssociation
```

returned the association class instead of the most likely expected `Role` class. This happened with
almost any method defined on Object, for example:

```ruby
module M
def m
1
end
end

role = Role.new
user = User.new
user.role = role

user.role.extend M
user.role.m # => raised undefined method m
role.kind_of?(M) # => should have been true
```

In the previous example, extending the value returned by `user.role` was actually extending
the `association` object instead of the actual role object.

Some other unfortunate effects of the way it used to be was that calling `user.role.to_json`
was trying to serialize the relation object along all it's metadata (params, parent, etc)
instead of the role object.

So I think that instead of having `her` users to think about explicitly doing `.fetch` for
their code to work, why not making it work as they should actually expect from any other
library like active record.

The way I approached this was by making the association method to return a BlankObject
(actually ActiveSupport::BlankObject) proxy that has *almost no method* defined, and
thus it cannot mask methods you actually intended to call on the fetched object.
So all methods on this proxy are forwarded to the fetched object, except for a handful
of them like `where`, `find`, etc, which get called on the association.

One important thing to notice is that I intentionally left out the `fetch` method
from the methods defined on the proxy. But I added an `association` one which
returns the association object upon which you can still call fetch, if you'd ever
need to `user.role.association.fetch`.

I consider the `fetch` method should not not be directly defined on the proxy as
no one should actually need to manually call it (as you never do with activerecord
to retrieve objects from the database). And if you do *need* to call `fetch`
explicitely, then I guess you are in that case aware you're working with an
non-active-record thingy but a `her` one. That's why you can still do `association.fetch`.

So this have been a quite large commit message, but I hope it explains why
I decided to spend a day fixing this on `her`, in the hope of avoiding others
the hard times I got this week while finding these unpexected hevaviours.

Besides all, thanks for making `her` it's such an awesome library.