README.md in draper-1.0.0.beta6 vs README.md in draper-1.0.0
- old
+ new
@@ -33,10 +33,12 @@
could be better written as:
```ruby
# app/decorators/article_decorator.rb
class ArticleDecorator < Draper::Decorator
+ delegate_all
+
def publication_status
if published?
"Published at #{published_at}"
else
"Unpublished"
@@ -47,11 +49,11 @@
source.published_at.strftime("%A, %B %e")
end
end
```
-Notice that the `published?` method can be called even though `ArticleDecorator` doesn't define it - the decorator delegates methods to the source model. However, we can override methods like `published_at` to add presentation-specific formatting, in which case we access the underlying model using the `source` method.
+Notice that the `published?` method can be called even though `ArticleDecorator` doesn't define it - thanks to `delegate_all`, the decorator delegates missing methods to the source model. However, we can override methods like `published_at` to add presentation-specific formatting, in which case we access the underlying model using the `source` method.
You might have heard this sort of decorator called a "presenter", an "exhibit", a "view model", or even just a "view" (in that nomenclature, what Rails calls "views" are actually "templates"). Whatever you call it, it's a great way to replace procedural helpers like the one above with "real" object-oriented programming.
Decorators are the ideal place to:
* format dates and times using `strftime`,
@@ -62,11 +64,11 @@
## Installation
Add Draper to your Gemfile:
```ruby
-gem 'draper', '~> 1.0'
+gem 'draper', '~> 1.0.0.beta6'
```
And run `bundle install` within your app's directory.
@@ -103,10 +105,12 @@
Decorators will delegate methods to the model where possible, which means in most cases you can replace a model with a decorator and your view won't notice the difference. When you need to get your hands on the underlying model the `source` method is your friend (and its aliases `model` and `to_source`):
```ruby
class ArticleDecorator < Draper::Decorator
+ delegate_all
+
def published_at
source.published_at.strftime("%A, %B %e")
end
end
```
@@ -156,18 +160,20 @@
@articles = ArticlesDecorator.decorate(Article.all)
```
Draper guesses the decorator used for each item from the name of the collection decorator (`ArticlesDecorator` becomes `ArticleDecorator`). If that fails, it falls back to using each item's `decorate` method. Alternatively, you can specify a decorator by overriding the collection decorator's `decorator_class` method.
-Some pagination gems add methods to `ActiveRecord::Relation`. For example, [Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method requires the collection to implement `current_page`, `total_pages`, and `limit_value`. To expose these on a collection decorator, you can simply delegate to `source`:
+Some pagination gems add methods to `ActiveRecord::Relation`. For example, [Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method requires the collection to implement `current_page`, `total_pages`, and `limit_value`. To expose these on a collection decorator, you can simply delegate to the `source`:
```ruby
class PaginatingDecorator < Draper::CollectionDecorator
- delegate :current_page, :total_pages, :limit_value, to: :source
+ delegate :current_page, :total_pages, :limit_value
end
```
+The `delegate` method used here is the same as that added by [Active Support](http://api.rubyonrails.org/classes/Module.html#method-i-delegate), except that the `:to` option is not required; it defaults to `:source` when omitted.
+
### Handy shortcuts
You can automatically decorate associated models:
```ruby
@@ -191,11 +197,11 @@
```
## Testing
-Draper supports RSpec and Minitest::Rails out of the box, and should work with Test::Unit as well.
+Draper supports RSpec, MiniTest::Rails, and Test::Unit, and will add the appropriate tests when you generate a decorator.
### RSpec
Your specs should live in `spec/decorators` (if not, you need to tag them with `type: :decorator`).
@@ -227,28 +233,19 @@
and inherit from it instead of directly from `Draper::Decorator`.
### Enforcing an interface between controllers and views
-If you want to strictly control which methods are called in your views, you can restrict the methods that the decorator delegates to the model. Use `denies` to blacklist methods:
+The `delegate_all` call at the top of your decorator means that all missing methods will delegated to the source. If you want to strictly control which methods are called in your views, you can choose to only delegate certain methods.
```ruby
class ArticleDecorator < Draper::Decorator
- # allow everything except `title` and `author` to be delegated
- denies :title, :author
+ delegate :title, :author
end
```
-or, better, use `allows` for a whitelist:
+As mentioned above for `CollectionDecorator`, the `delegate` method defaults to using `:source` if the `:to` option is omitted.
-```ruby
-class ArticleDecorator < Draper::Decorator
- # only allow `title` and `author` to be delegated to the model
- allows :title, :author
-end
-```
-
-You can prevent method delegation altogether using `denies_all`.
### Adding context
If you need to pass extra data to your decorators, you can use a `context` hash. Methods that create decorators take it as an option, for example