draper 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +216 -56
- data/lib/draper/automatic_delegation.rb +3 -3
- data/lib/draper/collection_decorator.rb +14 -10
- data/lib/draper/decoratable.rb +1 -1
- data/lib/draper/decoratable/equality.rb +1 -1
- data/lib/draper/decorated_association.rb +1 -1
- data/lib/draper/decorator.rb +46 -40
- data/lib/draper/delegation.rb +2 -2
- data/lib/draper/factory.rb +18 -14
- data/lib/draper/finders.rb +5 -5
- data/lib/draper/railtie.rb +1 -1
- data/lib/draper/version.rb +1 -1
- data/lib/generators/decorator/decorator_generator.rb +2 -2
- data/lib/generators/decorator/templates/decorator.rb +1 -1
- data/spec/draper/collection_decorator_spec.rb +41 -22
- data/spec/draper/decoratable_spec.rb +4 -4
- data/spec/draper/decorated_association_spec.rb +5 -5
- data/spec/draper/decorates_assigned_spec.rb +3 -3
- data/spec/draper/decorator_spec.rb +130 -91
- data/spec/draper/factory_spec.rb +30 -28
- data/spec/draper/finders_spec.rb +4 -4
- data/spec/dummy/app/decorators/post_decorator.rb +2 -2
- data/spec/dummy/fast_spec/post_decorator_spec.rb +2 -2
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +7 -7
- data/spec/dummy/test/minitest_helper.rb +1 -3
- data/spec/generators/decorator/decorator_generator_spec.rb +1 -0
- data/spec/support/shared_examples/decoratable_equality.rb +8 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f6bd44145856c0f804f44cd0bc8fc38490dd37d
|
4
|
+
data.tar.gz: fc320b6749db7c272ba791f118774f2bc01640dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d6fa20641f68112dba5e37c4e9b355b4f1f11f39cc3f7812e4e2631cf303bcc935f3c5d81265adaf0e96ae907bb60934b1eb047bdd2d2b9236eac9eb767a566
|
7
|
+
data.tar.gz: c92ef62f75eef8d105887c5be659171981ca59287da7b060d49755c608f3d1e50b0ef79da898c0586c2aaaccf50d7037059fe457cae2a3b3e294f18661f31535
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Draper Changelog
|
2
2
|
|
3
|
+
## 1.2.1
|
4
|
+
|
5
|
+
[28 commits by 4 authors](https://github.com/drapergem/draper/compare/v1.2.0...v1.2.1)
|
6
|
+
|
7
|
+
* [Document stubbing route helpers](https://github.com/drapergem/draper/commit/dbe8a81ca7d4d9ae87b4b62926a0ba6379397fbc)
|
8
|
+
|
9
|
+
* [Rename `source` to `object`. `source` still works, but will be depreciated in a future release.](https://github.com/drapergem/draper/commit/4b933ef39d252ecfe93c573a072633be545c49fb)
|
10
|
+
|
11
|
+
Various bugfixes, as always.
|
12
|
+
|
3
13
|
## 1.2.0
|
4
14
|
|
5
15
|
[78 commits by 14 authors](https://github.com/drapergem/draper/compare/v1.1.0...v1.2.0)
|
data/README.md
CHANGED
@@ -3,13 +3,20 @@
|
|
3
3
|
[![TravisCI Build Status](https://secure.travis-ci.org/drapergem/draper.png?branch=master)](http://travis-ci.org/drapergem/draper)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/drapergem/draper.png)](https://codeclimate.com/github/drapergem/draper)
|
5
5
|
|
6
|
-
Draper adds an object-oriented layer of presentation logic to your Rails
|
6
|
+
Draper adds an object-oriented layer of presentation logic to your Rails
|
7
|
+
application.
|
7
8
|
|
8
|
-
Without Draper, this functionality might have been tangled up in procedural
|
9
|
+
Without Draper, this functionality might have been tangled up in procedural
|
10
|
+
helpers or adding bulk to your models. With Draper decorators, you can wrap your
|
11
|
+
models with presentation-related logic to organise - and test - this layer of
|
12
|
+
your app much more effectively.
|
9
13
|
|
10
14
|
## Why Use a Decorator?
|
11
15
|
|
12
|
-
Imagine your application has an `Article` model. With Draper, you'd create a
|
16
|
+
Imagine your application has an `Article` model. With Draper, you'd create a
|
17
|
+
corresponding `ArticleDecorator`. The decorator wraps the model, and deals
|
18
|
+
*only* with presentational concerns. In the controller, you decorate the article
|
19
|
+
before handing it off to the view:
|
13
20
|
|
14
21
|
```ruby
|
15
22
|
# app/controllers/articles_controller.rb
|
@@ -18,9 +25,13 @@ def show
|
|
18
25
|
end
|
19
26
|
```
|
20
27
|
|
21
|
-
In the view, you can use the decorator in exactly the same way as you would have
|
28
|
+
In the view, you can use the decorator in exactly the same way as you would have
|
29
|
+
used the model. But whenever you start needing logic in the view or start
|
30
|
+
thinking about a helper method, you can implement a method on the decorator
|
31
|
+
instead.
|
22
32
|
|
23
|
-
Let's look at how you could convert an existing Rails helper to a decorator
|
33
|
+
Let's look at how you could convert an existing Rails helper to a decorator
|
34
|
+
method. You have this existing helper:
|
24
35
|
|
25
36
|
```ruby
|
26
37
|
# app/helpers/articles_helper.rb
|
@@ -33,17 +44,27 @@ def publication_status(article)
|
|
33
44
|
end
|
34
45
|
```
|
35
46
|
|
36
|
-
But it makes you a little uncomfortable. `publication_status` lives in a
|
47
|
+
But it makes you a little uncomfortable. `publication_status` lives in a
|
48
|
+
nebulous namespace spread across all controllers and view. Down the road, you
|
49
|
+
might want to display the publication status of a `Book`. And, of course, your
|
50
|
+
design calls for a slighly different formatting to the date for a `Book`.
|
37
51
|
|
38
|
-
Now your helper method can either switch based on the input class type (poor
|
52
|
+
Now your helper method can either switch based on the input class type (poor
|
53
|
+
Ruby style), or you break it out into two methods, `book_publication_status` and
|
54
|
+
`article_publication_status`. And keep adding methods for each publication
|
55
|
+
type...to the global helper namespace. And remember all the names. Ick.
|
39
56
|
|
40
|
-
Ruby thrives when we use Object-Oriented style. If you didn't know Rails'
|
57
|
+
Ruby thrives when we use Object-Oriented style. If you didn't know Rails'
|
58
|
+
helpers existed, you'd probably imagine that your view template could feature
|
59
|
+
something like this:
|
41
60
|
|
42
61
|
```erb
|
43
62
|
<%= @article.publication_status %>
|
44
63
|
```
|
45
64
|
|
46
|
-
Without a decorator, you'd have to implement the `publication_status` method in
|
65
|
+
Without a decorator, you'd have to implement the `publication_status` method in
|
66
|
+
the `Article` model. That method is presentation-centric, and thus does not
|
67
|
+
belong in a model.
|
47
68
|
|
48
69
|
Instead, you implement a decorator:
|
49
70
|
|
@@ -61,19 +82,27 @@ class ArticleDecorator < Draper::Decorator
|
|
61
82
|
end
|
62
83
|
|
63
84
|
def published_at
|
64
|
-
|
85
|
+
object.published_at.strftime("%A, %B %e")
|
65
86
|
end
|
66
87
|
end
|
67
88
|
```
|
68
89
|
|
69
|
-
Within the `publication_status` method we use the `published?` method. Where
|
90
|
+
Within the `publication_status` method we use the `published?` method. Where
|
91
|
+
does that come from? It's a method of the source `Article`, whose methods have
|
92
|
+
been made available on the decorator by the `delegate_all` call above.
|
70
93
|
|
71
|
-
You might have heard this sort of decorator called a "presenter", an "exhibit",
|
94
|
+
You might have heard this sort of decorator called a "presenter", an "exhibit",
|
95
|
+
a "view model", or even just a "view" (in that nomenclature, what Rails calls
|
96
|
+
"views" are actually "templates"). Whatever you call it, it's a great way to
|
97
|
+
replace procedural helpers like the one above with "real" object-oriented
|
98
|
+
programming.
|
72
99
|
|
73
100
|
Decorators are the ideal place to:
|
74
101
|
* format complex data for user display
|
75
|
-
* define commonly-used representations of an object, like a `name` method that
|
76
|
-
|
102
|
+
* define commonly-used representations of an object, like a `name` method that
|
103
|
+
combines `first_name` and `last_name` attributes
|
104
|
+
* mark up attributes with a little semantic HTML, like turning a `url` field
|
105
|
+
into a hyperlink
|
77
106
|
|
78
107
|
## Installation
|
79
108
|
|
@@ -85,11 +114,13 @@ gem 'draper', '~> 1.0'
|
|
85
114
|
|
86
115
|
And run `bundle install` within your app's directory.
|
87
116
|
|
88
|
-
If you're upgrading from a 0.x release, the major changes are outlined [in the
|
117
|
+
If you're upgrading from a 0.x release, the major changes are outlined [in the
|
118
|
+
wiki](https://github.com/drapergem/draper/wiki/Upgrading-to-1.0).
|
89
119
|
|
90
120
|
## Writing Decorators
|
91
121
|
|
92
|
-
Decorators inherit from `Draper::Decorator`, live in your `app/decorators`
|
122
|
+
Decorators inherit from `Draper::Decorator`, live in your `app/decorators`
|
123
|
+
directory, and are named for the model that they decorate:
|
93
124
|
|
94
125
|
```ruby
|
95
126
|
# app/decorators/article_decorator.rb
|
@@ -117,7 +148,8 @@ rails generate decorator Article
|
|
117
148
|
|
118
149
|
### Accessing Helpers
|
119
150
|
|
120
|
-
Normal Rails helpers are still useful for lots of tasks. Both Rails' provided
|
151
|
+
Normal Rails helpers are still useful for lots of tasks. Both Rails' provided
|
152
|
+
helper and those defined in your app can be accessed via the `h` method:
|
121
153
|
|
122
154
|
```ruby
|
123
155
|
class ArticleDecorator < Draper::Decorator
|
@@ -133,17 +165,20 @@ If writing `h.` frequently is getting you down, you can add...
|
|
133
165
|
include Draper::LazyHelpers
|
134
166
|
```
|
135
167
|
|
136
|
-
...at the top of your decorator class - you'll mix in a bazillion methods and
|
168
|
+
...at the top of your decorator class - you'll mix in a bazillion methods and
|
169
|
+
never have to type `h.` again.
|
137
170
|
(Note: the `capture` method is only available through `h` or `helpers`)
|
138
171
|
|
139
172
|
### Accessing the model
|
140
173
|
|
141
|
-
When writing decorator methods you'll usually need to access the wrapped model.
|
174
|
+
When writing decorator methods you'll usually need to access the wrapped model.
|
175
|
+
While you may choose to use delegation ([covered below](#delegating-methods))
|
176
|
+
for convenience, you can always use the `object` (or its alias `model`):
|
142
177
|
|
143
178
|
```ruby
|
144
179
|
class ArticleDecorator < Draper::Decorator
|
145
180
|
def published_at
|
146
|
-
|
181
|
+
object.published_at.strftime("%A, %B %e")
|
147
182
|
end
|
148
183
|
end
|
149
184
|
```
|
@@ -152,13 +187,16 @@ end
|
|
152
187
|
|
153
188
|
### Single Objects
|
154
189
|
|
155
|
-
Ok, so you've written a sweet decorator, now you're going to want to put it in
|
190
|
+
Ok, so you've written a sweet decorator, now you're going to want to put it in
|
191
|
+
action! A simple option is to call the `decorate` method on your model:
|
156
192
|
|
157
193
|
```ruby
|
158
194
|
@article = Article.first.decorate
|
159
195
|
```
|
160
196
|
|
161
|
-
This infers the decorator from the object being decorated. If you want more
|
197
|
+
This infers the decorator from the object being decorated. If you want more
|
198
|
+
control - say you want to decorate a `Widget` with a more general
|
199
|
+
`ProductDecorator` - then you can instantiate a decorator directly:
|
162
200
|
|
163
201
|
```ruby
|
164
202
|
@widget = ProductDecorator.new(Widget.first)
|
@@ -168,7 +206,8 @@ This infers the decorator from the object being decorated. If you want more cont
|
|
168
206
|
|
169
207
|
### Collections
|
170
208
|
|
171
|
-
If you have a whole bunch of objects, you can decorate them all in one fell
|
209
|
+
If you have a whole bunch of objects, you can decorate them all in one fell
|
210
|
+
swoop:
|
172
211
|
|
173
212
|
```ruby
|
174
213
|
@articles = ArticleDecorator.decorate_collection(Article.all)
|
@@ -180,9 +219,12 @@ If your collection is an ActiveRecord query, you can use this:
|
|
180
219
|
@articles = Article.popular.decorate
|
181
220
|
```
|
182
221
|
|
183
|
-
*Note:* In Rails 3, the `.all` method returns an array and not a query. Thus you
|
222
|
+
*Note:* In Rails 3, the `.all` method returns an array and not a query. Thus you
|
223
|
+
_cannot_ use the technique of `Article.all.decorate` in Rails 3. In Rails 4,
|
224
|
+
`.all` returns a query so this techique would work fine.
|
184
225
|
|
185
|
-
If you want to add methods to your decorated collection (for example, for
|
226
|
+
If you want to add methods to your decorated collection (for example, for
|
227
|
+
pagination), you can subclass `Draper::CollectionDecorator`:
|
186
228
|
|
187
229
|
```ruby
|
188
230
|
# app/decorators/articles_decorator.rb
|
@@ -198,11 +240,17 @@ end
|
|
198
240
|
@articles = ArticlesDecorator.decorate(Article.all)
|
199
241
|
```
|
200
242
|
|
201
|
-
Draper decorates each item using its `decorate` method. Alternatively, you can
|
243
|
+
Draper decorates each item using its `decorate` method. Alternatively, you can
|
244
|
+
specify a decorator by overriding the collection decorator's `decorator_class`
|
245
|
+
method, or by passing the `:with` option to the constructor.
|
202
246
|
|
203
247
|
#### Using pagination
|
204
248
|
|
205
|
-
Some pagination gems add methods to `ActiveRecord::Relation`. For example,
|
249
|
+
Some pagination gems add methods to `ActiveRecord::Relation`. For example,
|
250
|
+
[Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method
|
251
|
+
requires the collection to implement `current_page`, `total_pages`, and
|
252
|
+
`limit_value`. To expose these on a collection decorator, you can delegate to
|
253
|
+
the `object`:
|
206
254
|
|
207
255
|
```ruby
|
208
256
|
class PaginatingDecorator < Draper::CollectionDecorator
|
@@ -210,13 +258,18 @@ class PaginatingDecorator < Draper::CollectionDecorator
|
|
210
258
|
end
|
211
259
|
```
|
212
260
|
|
213
|
-
The `delegate` method used here is the same as that added by [Active
|
261
|
+
The `delegate` method used here is the same as that added by [Active
|
262
|
+
Support](http://api.rubyonrails.org/classes/Module.html#method-i-delegate),
|
263
|
+
except that the `:to` option is not required; it defaults to `:object` when
|
264
|
+
omitted.
|
214
265
|
|
215
|
-
[will_paginate](https://github.com/mislav/will_paginate) needs you to
|
266
|
+
[will_paginate](https://github.com/mislav/will_paginate) needs you to
|
267
|
+
`delegate :current_page, :per_page, :offset, :total_entries, :total_pages`.
|
216
268
|
|
217
269
|
### Decorating Associated Objects
|
218
270
|
|
219
|
-
You can automatically decorate associated models when the primary model is
|
271
|
+
You can automatically decorate associated models when the primary model is
|
272
|
+
decorated. Assuming an `Article` model has an associated `Author` object:
|
220
273
|
|
221
274
|
```ruby
|
222
275
|
class ArticleDecorator < Draper::Decorator
|
@@ -224,7 +277,8 @@ class ArticleDecorator < Draper::Decorator
|
|
224
277
|
end
|
225
278
|
```
|
226
279
|
|
227
|
-
When `ArticleDecorator` decorates an `Article`, it will also use
|
280
|
+
When `ArticleDecorator` decorates an `Article`, it will also use
|
281
|
+
`AuthorDecorator` to decorate the associated `Author`.
|
228
282
|
|
229
283
|
### Decorated Finders
|
230
284
|
|
@@ -236,21 +290,66 @@ class ArticleDecorator < Draper::Decorator
|
|
236
290
|
end
|
237
291
|
```
|
238
292
|
|
239
|
-
...which allows you to then call all the normal ActiveRecord-style finders on
|
293
|
+
...which allows you to then call all the normal ActiveRecord-style finders on
|
294
|
+
your `ArticleDecorator` and they'll return decorated objects:
|
240
295
|
|
241
296
|
```ruby
|
242
297
|
@article = ArticleDecorator.find(params[:id])
|
243
298
|
```
|
244
299
|
|
300
|
+
### When to decorate objects
|
301
|
+
|
302
|
+
Decorators are supposed to behave very much like the models they decorate, and
|
303
|
+
for that reason it is very tempting to just decorate your objects at the start
|
304
|
+
of your controller action and then use the decorators throughout. *Don't*.
|
305
|
+
|
306
|
+
Because decorators are designed to be consumed by the view, you should only be
|
307
|
+
accessing them there. Manipulate your models to get things ready, then decorate
|
308
|
+
at the last minute, right before you render the view. This avoids many of the
|
309
|
+
common pitfalls that arise from attempting to modify decorators (in particular,
|
310
|
+
collection decorators) after creating them.
|
311
|
+
|
312
|
+
To help you make your decorators read-only, we have the `decorates_assigned`
|
313
|
+
method in your controller. It adds a helper method that returns the decorated
|
314
|
+
version of an instance variable:
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
# app/controllers/articles_controller.rb
|
318
|
+
class ArticlesController < ApplicationController
|
319
|
+
decorates_assigned :article
|
320
|
+
|
321
|
+
def show
|
322
|
+
@article = Article.find(params[:id])
|
323
|
+
end
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
327
|
+
The `decorates_assigned :article` bit is roughly equivalent to
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
def article
|
331
|
+
@decorated_article ||= @article.decorate
|
332
|
+
end
|
333
|
+
helper_method :article
|
334
|
+
```
|
335
|
+
|
336
|
+
This means that you can just replace `@article` with `article` in your views and
|
337
|
+
you'll have access to an ArticleDecorator object instead. In your controller you
|
338
|
+
can continue to use the `@article` instance variable to manipulate the model -
|
339
|
+
for example, `@article.comments.build` to add a new blank comment for a form.
|
340
|
+
|
245
341
|
## Testing
|
246
342
|
|
247
|
-
Draper supports RSpec, MiniTest::Rails, and Test::Unit, and will add the
|
343
|
+
Draper supports RSpec, MiniTest::Rails, and Test::Unit, and will add the
|
344
|
+
appropriate tests when you generate a decorator.
|
248
345
|
|
249
346
|
### RSpec
|
250
347
|
|
251
|
-
Your specs are expected to live in `spec/decorators`. If you use a different
|
348
|
+
Your specs are expected to live in `spec/decorators`. If you use a different
|
349
|
+
path, you need to tag them with `type: :decorator`.
|
252
350
|
|
253
|
-
In a controller spec, you might want to check whether your instance variables
|
351
|
+
In a controller spec, you might want to check whether your instance variables
|
352
|
+
are being decorated properly. You can use the handy predicate matchers:
|
254
353
|
|
255
354
|
```ruby
|
256
355
|
assigns(:article).should be_decorated
|
@@ -259,7 +358,8 @@ assigns(:article).should be_decorated
|
|
259
358
|
assigns(:article).should be_decorated_with ArticleDecorator
|
260
359
|
```
|
261
360
|
|
262
|
-
Note that `model.decorate == model`, so your existing specs shouldn't break when
|
361
|
+
Note that `model.decorate == model`, so your existing specs shouldn't break when
|
362
|
+
you add the decoration.
|
263
363
|
|
264
364
|
#### Spork Users
|
265
365
|
|
@@ -271,13 +371,18 @@ require 'draper/test/rspec_integration'
|
|
271
371
|
|
272
372
|
### Isolated tests
|
273
373
|
|
274
|
-
In tests, Draper needs to build a view context to access helper methods. By
|
374
|
+
In tests, Draper needs to build a view context to access helper methods. By
|
375
|
+
default, it will create an `ApplicationController` and then use its view
|
376
|
+
context. If you are speeding up your test suite by testing each component in
|
377
|
+
isolation, you can eliminate this dependency by putting the following in your
|
378
|
+
`spec_helper` or similar:
|
275
379
|
|
276
380
|
```ruby
|
277
381
|
Draper::ViewContext.test_strategy :fast
|
278
382
|
```
|
279
383
|
|
280
|
-
In doing so, your decorators will no longer have access to your application's
|
384
|
+
In doing so, your decorators will no longer have access to your application's
|
385
|
+
helpers. If you need to selectively include such helpers, you can pass a block:
|
281
386
|
|
282
387
|
```ruby
|
283
388
|
Draper::ViewContext.test_strategy :fast do
|
@@ -285,13 +390,40 @@ Draper::ViewContext.test_strategy :fast do
|
|
285
390
|
end
|
286
391
|
```
|
287
392
|
|
393
|
+
#### Stubbing route helper functions
|
394
|
+
|
395
|
+
If you are writing isolated tests for Draper methods that call route helper
|
396
|
+
methods, you can stub them instead of needing to require Rails.
|
397
|
+
|
398
|
+
If you are using RSpec, minitest-rails, or the Test::Unit syntax of minitest,
|
399
|
+
you already have access to the Draper `helpers` in your tests since they
|
400
|
+
inherit from `Draper::TestCase`. If you are using minitest's spec syntax
|
401
|
+
without minitest-rails, you can explicitly include the Draper `helpers`:
|
402
|
+
|
403
|
+
```ruby
|
404
|
+
describe YourDecorator do
|
405
|
+
include Draper::ViewHelpers
|
406
|
+
end
|
407
|
+
```
|
408
|
+
|
409
|
+
Then you can stub the specific route helper functions you need using your
|
410
|
+
preferred stubbing technique (this example uses RSpec's `stub` method):
|
411
|
+
|
412
|
+
```ruby
|
413
|
+
helpers.stub(users_path: '/users')
|
414
|
+
```
|
415
|
+
|
288
416
|
## Advanced usage
|
289
417
|
|
290
418
|
### Shared Decorator Methods
|
291
419
|
|
292
|
-
You might have several decorators that share similar needs. Since decorators are
|
420
|
+
You might have several decorators that share similar needs. Since decorators are
|
421
|
+
just Ruby objects, you can use any normal Ruby technique for sharing
|
422
|
+
functionality.
|
293
423
|
|
294
|
-
In Rails controllers, common functionality is organized by having all
|
424
|
+
In Rails controllers, common functionality is organized by having all
|
425
|
+
controllers inherit from `ApplicationController`. You can apply this same
|
426
|
+
pattern to your decorators:
|
295
427
|
|
296
428
|
```ruby
|
297
429
|
# app/decorators/application_decorator.rb
|
@@ -300,7 +432,8 @@ class ApplicationDecorator < Draper::Decorator
|
|
300
432
|
end
|
301
433
|
```
|
302
434
|
|
303
|
-
Then modify your decorators to inherit from that `ApplicationDecorator` instead
|
435
|
+
Then modify your decorators to inherit from that `ApplicationDecorator` instead
|
436
|
+
of directly from `Draper::Decorator`:
|
304
437
|
|
305
438
|
```ruby
|
306
439
|
class ArticleDecorator < ApplicationDecorator
|
@@ -310,9 +443,12 @@ end
|
|
310
443
|
|
311
444
|
### Delegating Methods
|
312
445
|
|
313
|
-
When your decorator calls `delegate_all`, any method called on the decorator not
|
446
|
+
When your decorator calls `delegate_all`, any method called on the decorator not
|
447
|
+
defined in the decorator itself will be delegated to the decorated object. This
|
448
|
+
is a very permissive interface.
|
314
449
|
|
315
|
-
If you want to strictly control which methods are called within views, you can
|
450
|
+
If you want to strictly control which methods are called within views, you can
|
451
|
+
choose to only delegate certain methods from the decorator to the source model:
|
316
452
|
|
317
453
|
```ruby
|
318
454
|
class ArticleDecorator < Draper::Decorator
|
@@ -320,7 +456,8 @@ class ArticleDecorator < Draper::Decorator
|
|
320
456
|
end
|
321
457
|
```
|
322
458
|
|
323
|
-
We omit the `:to` argument here as it defaults to the `
|
459
|
+
We omit the `:to` argument here as it defaults to the `object` being decorated.
|
460
|
+
You could choose to delegate methods to other places like this:
|
324
461
|
|
325
462
|
```ruby
|
326
463
|
class ArticleDecorator < Draper::Decorator
|
@@ -329,7 +466,8 @@ class ArticleDecorator < Draper::Decorator
|
|
329
466
|
end
|
330
467
|
```
|
331
468
|
|
332
|
-
From your view template, assuming `@article` is decorated, you could do any of
|
469
|
+
From your view template, assuming `@article` is decorated, you could do any of
|
470
|
+
the following:
|
333
471
|
|
334
472
|
```ruby
|
335
473
|
@article.title # Returns the article's `.title`
|
@@ -340,15 +478,19 @@ From your view template, assuming `@article` is decorated, you could do any of t
|
|
340
478
|
|
341
479
|
### Adding context
|
342
480
|
|
343
|
-
If you need to pass extra data to your decorators, you can use a `context` hash.
|
481
|
+
If you need to pass extra data to your decorators, you can use a `context` hash.
|
482
|
+
Methods that create decorators take it as an option, for example:
|
344
483
|
|
345
484
|
```ruby
|
346
485
|
Article.first.decorate(context: {role: :admin})
|
347
486
|
```
|
348
487
|
|
349
|
-
The value passed to the `:context` option is then available in the decorator
|
488
|
+
The value passed to the `:context` option is then available in the decorator
|
489
|
+
through the `context` method.
|
350
490
|
|
351
|
-
If you use `decorates_association`, the context of the parent decorator is
|
491
|
+
If you use `decorates_association`, the context of the parent decorator is
|
492
|
+
passed to the associated decorators. You can override this with the `:context`
|
493
|
+
option:
|
352
494
|
|
353
495
|
```ruby
|
354
496
|
class ArticleDecorator < Draper::Decorator
|
@@ -356,7 +498,8 @@ class ArticleDecorator < Draper::Decorator
|
|
356
498
|
end
|
357
499
|
```
|
358
500
|
|
359
|
-
or, if you want to modify the parent's context, use a lambda that takes a hash
|
501
|
+
or, if you want to modify the parent's context, use a lambda that takes a hash
|
502
|
+
and returns a new hash:
|
360
503
|
|
361
504
|
```ruby
|
362
505
|
class ArticleDecorator < Draper::Decorator
|
@@ -367,7 +510,9 @@ end
|
|
367
510
|
|
368
511
|
### Specifying Decorators
|
369
512
|
|
370
|
-
When you're using `decorates_association`, Draper uses the `decorate` method on
|
513
|
+
When you're using `decorates_association`, Draper uses the `decorate` method on
|
514
|
+
the associated record(s) to perform the decoration. If you want use a specific
|
515
|
+
decorator, you can use the `:with` option:
|
371
516
|
|
372
517
|
```ruby
|
373
518
|
class ArticleDecorator < Draper::Decorator
|
@@ -375,11 +520,15 @@ class ArticleDecorator < Draper::Decorator
|
|
375
520
|
end
|
376
521
|
```
|
377
522
|
|
378
|
-
For a collection association, you can specify a `CollectionDecorator` subclass,
|
523
|
+
For a collection association, you can specify a `CollectionDecorator` subclass,
|
524
|
+
which is applied to the whole collection, or a singular `Decorator` subclass,
|
525
|
+
which is applied to each item individually.
|
379
526
|
|
380
527
|
### Scoping Associations
|
381
528
|
|
382
|
-
If you want your decorated association to be ordered, limited, or otherwise
|
529
|
+
If you want your decorated association to be ordered, limited, or otherwise
|
530
|
+
scoped, you can pass a `:scope` option to `decorates_association`, which will be
|
531
|
+
applied to the collection *before* decoration:
|
383
532
|
|
384
533
|
```ruby
|
385
534
|
class ArticleDecorator < Draper::Decorator
|
@@ -389,9 +538,13 @@ end
|
|
389
538
|
|
390
539
|
### Proxying Class Methods
|
391
540
|
|
392
|
-
If you want to proxy class methods to the wrapped model class, including when
|
541
|
+
If you want to proxy class methods to the wrapped model class, including when
|
542
|
+
using `decorates_finders`, Draper needs to know the model class. By default, it
|
543
|
+
assumes that your decorators are named `SomeModelDecorator`, and then attempts
|
544
|
+
to proxy unknown class methods to `SomeModel`.
|
393
545
|
|
394
|
-
If your model name can't be inferred from your decorator name in this way, you
|
546
|
+
If your model name can't be inferred from your decorator name in this way, you
|
547
|
+
need to use the `decorates` method:
|
395
548
|
|
396
549
|
```ruby
|
397
550
|
class MySpecialArticleDecorator < Draper::Decorator
|
@@ -403,11 +556,18 @@ This is only necessary when proxying class methods.
|
|
403
556
|
|
404
557
|
### Making models decoratable
|
405
558
|
|
406
|
-
Models get their `decorate` method from the `Draper::Decoratable` module, which
|
559
|
+
Models get their `decorate` method from the `Draper::Decoratable` module, which
|
560
|
+
is included in `ActiveRecord::Base` and `Mongoid::Document` by default. If
|
561
|
+
you're [using another
|
562
|
+
ORM](https://github.com/drapergem/draper/wiki/Using-other-ORMs) (including
|
563
|
+
versions of Mongoid prior to 3.0), or want to decorate plain old Ruby objects,
|
564
|
+
you can include this module manually.
|
407
565
|
|
408
566
|
## Contributors
|
409
567
|
|
410
|
-
Draper was conceived by Jeff Casimir and heavily refined by Steve Klabnik and a
|
568
|
+
Draper was conceived by Jeff Casimir and heavily refined by Steve Klabnik and a
|
569
|
+
great community of open source
|
570
|
+
[contributors](https://github.com/drapergem/draper/contributors).
|
411
571
|
|
412
572
|
### Core Team
|
413
573
|
|