rails/rails — pull request #7520 by al2o3cr (2012-09-04 15:25:31+00:00)
Title: Add wrap_with to Relation; simplify decorator / presenter / etc. code

The attached code adds a `wrap_with` method to Relation that wraps objects retrieved from the relation in the specified class. A trivial example:

```ruby
class UserWrapper < DelegateClass(User)
def magic_thing
puts 'wat'
end
end

User.where(:name => 'Bob').wrap_with(UserWrapper).first.magic_thing # => prints 'wat'
```

A short test is included - suggestions for additional testing (or more meaningful testing) are welcome.

There are also a number of additional features that could be included here, if they make sense:

* wrapping with additional classes may be useful; currently, chaining another `wrap_with` call overwrites the value set in the first one. This would be a simple change, given the existing plumbing for dealing with multi-valued data on Relation.

* passing additional arguments to the method could be useful; for instance, `some_relation.wrap_with(SomeClass, :foo, :bar, :baz)` would pass the additional arguments on to the constructor, so each record in `some_relation` would be wrapped via `SomeClass.new(record, :foo, :bar, :baz)`. Again, a fairly trivial modification.

* for extreme cases, passing a block may make more sense. For instance:
```ruby
some_relation.wrap_with(SomeClass) { |some_class| some_class.do_something }
# which wraps as:
SomeClass.new(record).tap { |some_class| some_class.do_something }
```

* of course, there's also an argument that a zero-arg block version might make sense:
```ruby
some_relation.wrap_with { |record| SomeClass.new(record) }
```
Here, `wrap_with` is just calling the block with the record directly.

* the current code doesn't do anything when building / creating new records; it was extracted from a live app that used `wrap_with` solely for read-only views. I'm not certain what the desirable behavior is here.