drape 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +27 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +1159 -0
  6. data/.travis.yml +14 -0
  7. data/.yardopts +1 -0
  8. data/CHANGELOG.md +230 -0
  9. data/CONTRIBUTING.md +20 -0
  10. data/Gemfile +16 -0
  11. data/Guardfile +26 -0
  12. data/LICENSE +7 -0
  13. data/README.md +592 -0
  14. data/Rakefile +76 -0
  15. data/drape.gemspec +31 -0
  16. data/gemfiles/5.0.gemfile +8 -0
  17. data/lib/drape.rb +63 -0
  18. data/lib/drape/automatic_delegation.rb +55 -0
  19. data/lib/drape/collection_decorator.rb +102 -0
  20. data/lib/drape/decoratable.rb +93 -0
  21. data/lib/drape/decoratable/equality.rb +26 -0
  22. data/lib/drape/decorated_association.rb +33 -0
  23. data/lib/drape/decorates_assigned.rb +44 -0
  24. data/lib/drape/decorator.rb +282 -0
  25. data/lib/drape/delegation.rb +13 -0
  26. data/lib/drape/factory.rb +91 -0
  27. data/lib/drape/finders.rb +36 -0
  28. data/lib/drape/helper_proxy.rb +43 -0
  29. data/lib/drape/helper_support.rb +5 -0
  30. data/lib/drape/lazy_helpers.rb +13 -0
  31. data/lib/drape/railtie.rb +69 -0
  32. data/lib/drape/tasks/test.rake +9 -0
  33. data/lib/drape/test/devise_helper.rb +30 -0
  34. data/lib/drape/test/minitest_integration.rb +6 -0
  35. data/lib/drape/test/rspec_integration.rb +20 -0
  36. data/lib/drape/test_case.rb +42 -0
  37. data/lib/drape/undecorate.rb +9 -0
  38. data/lib/drape/version.rb +3 -0
  39. data/lib/drape/view_context.rb +104 -0
  40. data/lib/drape/view_context/build_strategy.rb +46 -0
  41. data/lib/drape/view_helpers.rb +34 -0
  42. data/lib/generators/controller_override.rb +17 -0
  43. data/lib/generators/mini_test/decorator_generator.rb +20 -0
  44. data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
  45. data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
  46. data/lib/generators/rails/decorator_generator.rb +36 -0
  47. data/lib/generators/rails/templates/decorator.rb +19 -0
  48. data/lib/generators/rspec/decorator_generator.rb +9 -0
  49. data/lib/generators/rspec/templates/decorator_spec.rb +4 -0
  50. data/lib/generators/test_unit/decorator_generator.rb +9 -0
  51. data/lib/generators/test_unit/templates/decorator_test.rb +4 -0
  52. data/spec/draper/collection_decorator_spec.rb +305 -0
  53. data/spec/draper/decoratable/equality_spec.rb +10 -0
  54. data/spec/draper/decoratable_spec.rb +203 -0
  55. data/spec/draper/decorated_association_spec.rb +85 -0
  56. data/spec/draper/decorates_assigned_spec.rb +70 -0
  57. data/spec/draper/decorator_spec.rb +828 -0
  58. data/spec/draper/factory_spec.rb +250 -0
  59. data/spec/draper/finders_spec.rb +165 -0
  60. data/spec/draper/helper_proxy_spec.rb +61 -0
  61. data/spec/draper/lazy_helpers_spec.rb +21 -0
  62. data/spec/draper/undecorate_spec.rb +19 -0
  63. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  64. data/spec/draper/view_context_spec.rb +160 -0
  65. data/spec/draper/view_helpers_spec.rb +8 -0
  66. data/spec/dummy/.gitignore +21 -0
  67. data/spec/dummy/Rakefile +6 -0
  68. data/spec/dummy/app/assets/config/manifest.js +3 -0
  69. data/spec/dummy/app/assets/images/.keep +0 -0
  70. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  71. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  72. data/spec/dummy/app/assets/javascripts/channels/.keep +0 -0
  73. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  74. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  75. data/spec/dummy/app/channels/application_cable/connection.rb +5 -0
  76. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  77. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  78. data/spec/dummy/app/controllers/posts_controller.rb +21 -0
  79. data/spec/dummy/app/decorators/mongoid_post_decorator.rb +4 -0
  80. data/spec/dummy/app/decorators/post_decorator.rb +59 -0
  81. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  82. data/spec/dummy/app/jobs/application_job.rb +2 -0
  83. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  84. data/spec/dummy/app/mailers/post_mailer.rb +18 -0
  85. data/spec/dummy/app/models/admin.rb +5 -0
  86. data/spec/dummy/app/models/application_record.rb +3 -0
  87. data/spec/dummy/app/models/concerns/.keep +0 -0
  88. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  89. data/spec/dummy/app/models/post.rb +3 -0
  90. data/spec/dummy/app/models/user.rb +5 -0
  91. data/spec/dummy/app/views/layouts/application.html.erb +9 -0
  92. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  93. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  94. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +31 -0
  95. data/spec/dummy/app/views/posts/_post.html.erb +40 -0
  96. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  97. data/spec/dummy/bin/bundle +3 -0
  98. data/spec/dummy/bin/rails +9 -0
  99. data/spec/dummy/bin/rake +9 -0
  100. data/spec/dummy/bin/setup +34 -0
  101. data/spec/dummy/bin/spring +15 -0
  102. data/spec/dummy/bin/update +29 -0
  103. data/spec/dummy/config.ru +5 -0
  104. data/spec/dummy/config/application.rb +21 -0
  105. data/spec/dummy/config/boot.rb +2 -0
  106. data/spec/dummy/config/cable.yml +10 -0
  107. data/spec/dummy/config/database.yml +25 -0
  108. data/spec/dummy/config/environment.rb +5 -0
  109. data/spec/dummy/config/environments/development.rb +51 -0
  110. data/spec/dummy/config/environments/production.rb +91 -0
  111. data/spec/dummy/config/environments/test.rb +42 -0
  112. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
  113. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  114. data/spec/dummy/config/initializers/assets.rb +11 -0
  115. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  116. data/spec/dummy/config/initializers/callback_terminator.rb +6 -0
  117. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  118. data/spec/dummy/config/initializers/devise.rb +3 -0
  119. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  120. data/spec/dummy/config/initializers/inflections.rb +16 -0
  121. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  122. data/spec/dummy/config/initializers/per_form_csrf_tokens.rb +4 -0
  123. data/spec/dummy/config/initializers/request_forgery_protection.rb +4 -0
  124. data/spec/dummy/config/initializers/session_store.rb +3 -0
  125. data/spec/dummy/config/initializers/ssl_options.rb +4 -0
  126. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  127. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  128. data/spec/dummy/config/locales/en.yml +23 -0
  129. data/spec/dummy/config/mongoid.yml +16 -0
  130. data/spec/dummy/config/puma.rb +47 -0
  131. data/spec/dummy/config/routes.rb +8 -0
  132. data/spec/dummy/config/secrets.yml +22 -0
  133. data/spec/dummy/config/spring.rb +6 -0
  134. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +7 -0
  135. data/spec/dummy/db/schema.rb +19 -0
  136. data/spec/dummy/db/seeds.rb +2 -0
  137. data/spec/dummy/lib/assets/.keep +0 -0
  138. data/spec/dummy/lib/tasks/.keep +0 -0
  139. data/spec/dummy/lib/tasks/test.rake +16 -0
  140. data/spec/dummy/log/.keep +0 -0
  141. data/spec/dummy/public/404.html +67 -0
  142. data/spec/dummy/public/422.html +67 -0
  143. data/spec/dummy/public/500.html +66 -0
  144. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  145. data/spec/dummy/public/apple-touch-icon.png +0 -0
  146. data/spec/dummy/public/favicon.ico +0 -0
  147. data/spec/dummy/public/robots.txt +5 -0
  148. data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +12 -0
  149. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  150. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  151. data/spec/dummy/spec/decorators/post_decorator_spec.rb +66 -0
  152. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  153. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  154. data/spec/dummy/spec/mailers/post_mailer_spec.rb +33 -0
  155. data/spec/dummy/spec/models/mongoid_post_spec.rb +8 -0
  156. data/spec/dummy/spec/models/post_spec.rb +6 -0
  157. data/spec/dummy/spec/shared_examples/decoratable.rb +26 -0
  158. data/spec/dummy/spec/spec_helper.rb +8 -0
  159. data/spec/dummy/test/controllers/.keep +0 -0
  160. data/spec/dummy/test/fixtures/.keep +0 -0
  161. data/spec/dummy/test/fixtures/files/.keep +0 -0
  162. data/spec/dummy/test/helpers/.keep +0 -0
  163. data/spec/dummy/test/integration/.keep +0 -0
  164. data/spec/dummy/test/mailers/.keep +0 -0
  165. data/spec/dummy/test/models/.keep +0 -0
  166. data/spec/dummy/test/test_helper.rb +10 -0
  167. data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
  168. data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
  169. data/spec/generators/controller/controller_generator_spec.rb +24 -0
  170. data/spec/generators/decorator/decorator_generator_spec.rb +94 -0
  171. data/spec/integration/integration_spec.rb +68 -0
  172. data/spec/performance/active_record.rb +4 -0
  173. data/spec/performance/benchmark.rb +57 -0
  174. data/spec/performance/decorators.rb +41 -0
  175. data/spec/performance/models.rb +20 -0
  176. data/spec/spec_helper.rb +41 -0
  177. data/spec/support/dummy_app.rb +88 -0
  178. data/spec/support/matchers/have_text.rb +50 -0
  179. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  180. data/spec/support/shared_examples/view_helpers.rb +39 -0
  181. metadata +497 -0
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+
3
+ services:
4
+ - mongodb
5
+
6
+ rvm:
7
+ - 2.3.1
8
+
9
+ env:
10
+ - "RAILS_VERSION=5.0"
11
+
12
+ addons:
13
+ code_climate:
14
+ repo_token: 85e7394726a531f2ae6520456b1f44488c4c22fc656cda26b843eb2eb4b58612
@@ -0,0 +1 @@
1
+ yardoc 'lib/drape/**/*.rb' -m markdown --no-private
@@ -0,0 +1,230 @@
1
+ # Drape Changelog
2
+
3
+ ## 2.1.0 - 2015-03-26
4
+
5
+ * Cleared most issues and merged a few PRs
6
+ * Improved behavior when decorating structs
7
+ * Improved how equality is handled
8
+ * Minor improvements to the README
9
+
10
+ ## 2.0.0 - 2015-03-26
11
+
12
+ Working to breathe new life into the project by shedding baggage.
13
+
14
+ * Rails 3.2 support dropped
15
+ * Ruby 1.9.3 and 2.0 support dropped
16
+ * Add support for Rails 4.2 and Ruby 2.2
17
+ * Rewrite tests to get over RSpec deprecations
18
+ * Get RSpec up to 3.2
19
+ * Try to un-screw the challenges of ActiveModelSerializers
20
+
21
+ Due to the breakages of dropping legacy support, we've bumped the major version. From here,
22
+ development effort will likely focus on a version 3.0 that removes features and simplifies
23
+ usage of the library.
24
+
25
+ ## 1.3.0 - 2013-10-26
26
+
27
+ [30 commits by 11 authors](https://github.com/drapegem/drape/compare/v1.2.1...v1.3.0)
28
+
29
+ * [Add `decorator_class?` method](https://github.com/drapegem/drape/commit/53e1df5c3ee169144a2778c6d2ee13cc6af99429)
30
+
31
+ * [Clear ViewContext before specs instead of after](https://github.com/drapegem/drape/pull/547)
32
+
33
+ * [Add alias method `#{model_name}` to the decorated object ](https://github.com/drapegem/drape/commit/f5f27243c3f0c37bff4872e1e78521e570ff1e4f)
34
+
35
+ * [Hook into `controller_generator` and `scaffold_controller_generator` instead of resource generator](https://github.com/drapegem/drape/commit/cd4f298987c3b4ad8046563ad4a087055fc7efe2)
36
+
37
+ * [Delegate `to_s` method to the object](https://github.com/drapegem/drape/commit/58b8181050c2a9a86f54660e7bb6bfefa5fd0b64)
38
+
39
+ ## 1.2.1 - 2013-05-05
40
+
41
+ [28 commits by 4 authors](https://github.com/drapegem/drape/compare/v1.2.0...v1.2.1)
42
+
43
+ * [Document stubbing route helpers](https://github.com/drapegem/drape/commit/dbe8a81ca7d4d9ae87b4b62926a0ba6379397fbc)
44
+
45
+ * [Rename `source` to `object`. `source` still works, but will be deprecated in a future release.](https://github.com/drapegem/drape/commit/4b933ef39d252ecfe93c573a072633be545c49fb)
46
+
47
+ Various bugfixes, as always.
48
+
49
+ ## 1.2.0 - 2013-04-01
50
+
51
+ [78 commits by 14 authors](https://github.com/drapegem/drape/compare/v1.1.0...v1.2.0)
52
+
53
+ * [Added license to the gemspec](https://github.com/drapegem/drape/commit/731fa85f7744a12da1364a3aa94cdf6994efa9e2)
54
+
55
+ * [Improvements in serialization](https://github.com/drapegem/drape/pull/448)
56
+
57
+ * [Fix support for Guard in development](https://github.com/drapegem/drape/commit/93c95200277fd3922e30e74c7a7e05563747e896)
58
+
59
+ * [Improved support for #capture](https://github.com/drapegem/drape/commit/efb934a6f59b9d8afe4a7fe29e9a94aae983b05c)
60
+
61
+ * [CollectionDecorator now has #decorated?](https://github.com/drapegem/drape/commit/65e3c4e4573173b510440b7e80f95a87109a1d15)
62
+
63
+ * [Added #respond_to_missing?](https://github.com/drapegem/drape/commit/11bb59bcf89f8e0be4ba2851eb78634caf783ecd)
64
+
65
+ * [Add proper STI support](https://github.com/drapegem/drape/commit/7802d97446cf6ea130a66c2781f5a7a087d28c0a)
66
+
67
+ * [Added before_remove_const callback for ActiveSupport](https://github.com/drapegem/drape/commit/9efda27c6a4f8680df4fad8f67ecb58e3f91703f)
68
+
69
+ * [Accept a lambda for context](https://github.com/drapegem/drape/commit/3ab3b35e875b8b2bd99a57e4add388313e765230)
70
+
71
+ * [Start testing against Ruby 2.0.0](https://github.com/drapegem/drape/commit/dbd1cbceedb0ddb3f060196cd31eb967db8a370b)
72
+
73
+ * [Fix our use of #scoped per Rails 4 deprecation](https://github.com/haines/drape/commit/47ee29c3b739eee3fc28a561432ad2363c14813c)
74
+
75
+ * [Properly swallow NameErrors](https://github.com/haines/drape/commit/09ad84fb712a30dd4302b9daa03d11281ac7d169)
76
+
77
+ * [Delegate CollectionDecorator#kind_of? to the underlying collection](https://github.com/drapegem/drape/commit/d5975f2c5b810306a96d9485fd39d550896dc2a1)
78
+
79
+ * [Make CollectionDecorators respond to #decorated_with?](https://github.com/drapegem/drape/commit/dc430b3e82de0d9cae86f7297f816e5b69d9ca58)
80
+
81
+ * [Avoid using #extend in Decorator#== for performance reasons](https://github.com/drapegem/drape/commit/205a0d43b4141f7b1756fe2b44b877545eb37517)
82
+
83
+ ## 1.1.0 - 2013-01-28
84
+
85
+ [44 commits by 6 authors](https://github.com/drapegem/drape/compare/v1.0.0...v1.1.0)
86
+
87
+ * README improvements.
88
+ * Rails 4 compatibility.
89
+ [b2401c7](https://github.com/drapegem/drape/commit/b2401c71e092470e3b912b5da475115c22b55734)
90
+ * Added support for testing decorators without loading `ApplicationController`.
91
+ See the [README](https://github.com/drapegem/drape/blob/v1.1.0/README.md#isolated-tests) for details.
92
+ [4d0181f](https://github.com/drapegem/drape/commit/4d0181fb9c65dc769b05ed19bfcec2119d6e88f7)
93
+ * Improved the `==` method to check for `decorated?` before attempting to
94
+ compare with `source`.
95
+ [6c31617](https://github.com/drapegem/drape/commit/6c316176f5039a5861491fbcaa81f64ac4b36768)
96
+ * Changed the way helpers are accessed, so that helper methods may be stubbed
97
+ in tests.
98
+ [7a04619](https://github.com/drapegem/drape/commit/7a04619a06f832801bd4aedaaf5985d6e3e5e1af)
99
+ * Made the Devise test helper `sign_in` method independent of mocking
100
+ framework.
101
+ [b0902ab](https://github.com/drapegem/drape/commit/b0902ab0fe01916b7fddb0a3d97aa0c7cca09482)
102
+ * Stopped attempting to call `to_a` on decorated objects (a now-redundant lazy
103
+ query workaround).
104
+ [34c6390](https://github.com/drapegem/drape/commit/34c6390583f7fc7704d04e38bc974b65fc92517c)
105
+ * Fixed a minor bug where view contexts could be accidentally shared between
106
+ tests.
107
+ [3d07cb3](https://github.com/drapegem/drape/commit/3d07cb387b1cae6f97897dfb85512e30f5e888e9)
108
+ * Improved helper method performance.
109
+ [e6f88a5](https://github.com/drapegem/drape/commit/e6f88a5e7dada3f9db480e13e16d1acc964ba098)
110
+ * Our specs now use the new RSpec `expect( ).to` syntax.
111
+ [9a3b319](https://github.com/drapegem/drape/commit/9a3b319d6d54cd78fb2654a94bbe893e36359754)
112
+
113
+ ## 1.0.0 - 2013-01-14
114
+
115
+ [249 commits by 19 authors](https://github.com/drapegem/drape/compare/v0.18.0...v1.0.0)
116
+
117
+ Major changes are described [in the upgrade guide](https://github.com/drapegem/drape/wiki/Upgrading-to-1.0).
118
+
119
+ * Infer collection decorators.
120
+ [e8253df](https://github.com/drapegem/drape/commit/e8253df7dc6c90a542444c0f4ef289909fce4f90)
121
+ * Prevent calls to `scoped` on decorated associations.
122
+ [5dcc6c3](https://github.com/drapegem/drape/commit/5dcc6c31ecf408753158d15fed9fb23fbfdc3734)
123
+ * Add `helper` method to tests.
124
+ [551961e](https://github.com/drapegem/drape/commit/551961e72ee92355bc9c848bedfcc573856d12b0)
125
+ * Inherit method security.
126
+ [1865ed3](https://github.com/drapegem/drape/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d)
127
+ * Test against all versions of Rails 3.
128
+ [1865ed3](https://github.com/drapegem/drape/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d)
129
+ * Pretend to be `instance_of?(source.class)`.
130
+ [30d209f](https://github.com/drapegem/drape/commit/30d209f990847e84b221ac798e84b976f5775cc0)
131
+ * Remove security from `Decorator`. Do manual delegation with `:delegate`.
132
+ [c6f8aaa](https://github.com/drapegem/drape/commit/c6f8aaa2b2bd4679738050aede2503aa8e9db130)
133
+ * Add generators for MiniTest.
134
+ [1fac02b](https://github.com/drapegem/drape/commit/1fac02b65b15e32f06e8292cb858c97cb1c1da2c)
135
+ * Test against edge rails.
136
+ [e9b71e3](https://github.com/drapegem/drape/commit/e9b71e3cf55a800b48c083ff257a7c1cbe1b601b)
137
+
138
+ ### 1.0.0.beta6 - 2012-12-31
139
+
140
+ * Fix up README to include changes made.
141
+ [5e6e4d1](https://github.com/drapegem/drape/commit/5e6e4d11b1e0c07c12b6b1e87053bc3f50ef2ab6)
142
+ * `CollectionDecorator` no longer freezes its collection: direct access is
143
+ discouraged by making access private.
144
+ [c6d60e6](https://github.com/drapegem/drape/commit/c6d60e6577ed396385f3f1151c3f188fe47e9a57)
145
+ * A fix for `Decoratable#==`.
146
+ [e4fa239](https://github.com/drapegem/drape/commit/e4fa239d84e8e9d6a490d785abb3953acc28fa65)
147
+ * Ensure we coerce to an array in the right place.
148
+ [9eb9fc9](https://github.com/drapegem/drape/commit/9eb9fc909c372ea1c2392d05594fa75a5c08b095)
149
+
150
+ ### 1.0.0.beta5 - 2012-12-27
151
+
152
+ * Change CollectionDecorator to freeze its collection.
153
+ [04d7796](https://github.com/drapegem/drape/commit/04d779615c43580409083a71661489e1bbf91ad4)
154
+ * Bugfix on `CollectionDecorator#to_s`.
155
+ [eefd7d0](https://github.com/drapegem/drape/commit/eefd7d09cac97d531b9235246378c3746d153f08)
156
+ * Upgrade `request_store` dependency to take advantage of a bugfix.
157
+ [9f17212](https://github.com/drapegem/drape/commit/9f17212fd1fb656ef1314327d60fe45e0acf60a2)
158
+
159
+ ### 1.0.0.beta4 - 2012-12-18
160
+
161
+ * Fixed a race condition with capybara integration.
162
+ [e794649](https://github.com/drapegem/drape/commit/e79464931e7b98c85ed5d78ed9ca38d51f43006e)
163
+ * `[]` can be decorated again.
164
+ [597fbdf](https://github.com/drapegem/drape/commit/597fbdf0c80583f5ea6df9f7350fefeaa0cca989)
165
+ * `model == decorator` as well as `decorator == model`.
166
+ [46f8a68](https://github.com/drapegem/drape/commit/46f8a6823c50c13e5c9ab3c07723f335c4e291bc)
167
+ * Preliminary Mongoid integration.
168
+ [892d195](https://github.com/drapegem/drape/commit/892d1954202c61fd082a07213c8d4a23560687bc)
169
+ * Add a helper method `sign_in` for devise in decorator specs.
170
+ [66a3009](https://github.com/drapegem/drape/commit/66a30093ed4207d02d8fa60bda4df2da091d85a3)
171
+ * Brought back `context`.
172
+ [9609156](https://github.com/drapegem/drape/commit/9609156b997b3a469386eef3a5f043b24d8a2fba)
173
+ * Fixed issue where classes were incorrectly being looked up.
174
+ [ee2a015](https://github.com/drapegem/drape/commit/ee2a015514ff87dfd2158926457e988c2fc3fd79)
175
+ * Integrate RequestStore for per-request storage.
176
+ [fde1cde](https://github.com/drapegem/drape/commit/fde1cde9adfb856750c1f616d8b62d221ef97fc6)
177
+
178
+ ### 1.0.0.beta3 - 2012-12-03
179
+
180
+ * Relaxed Rails version requirement to 3.0. Support for < 3.2 should be
181
+ considered experimental. Please file bug reports.
182
+
183
+ ### 1.0.0.beta2 - 2012-12-03
184
+
185
+ * `has_finders` is now `decorates_finders`.
186
+ [33f18aa](https://github.com/drapegem/drape/commit/33f18aa062e0d3848443dbd81047f20d5665579f)
187
+ * If a finder method is used, and the source class is not set and cannot be
188
+ inferred, an `UninferrableSourceError` is raised.
189
+ [8ef5bf2](https://github.com/drapegem/drape/commit/8ef5bf2f02f7033e3cd4f1f5de7397b02c984fe3)
190
+ * Class methods are now properly delegated again.
191
+ [731995a](https://github.com/drapegem/drape/commit/731995a5feac4cd06cf9328d2892c0eca9992db6)
192
+ * We no longer `respond_to?` private methods on the source.
193
+ [18ebac8](https://github.com/drapegem/drape/commit/18ebac81533a6413aa20a3c26f23e91d0b12b031)
194
+ * Rails versioning relaxed to support Rails 4.
195
+ [8bfd393](https://github.com/drapegem/drape/commit/8bfd393b5baa7aa1488076a5e2cb88648efaa815)
196
+
197
+ ### 1.0.0.beta1 - 2012-11-30
198
+
199
+ * Renaming `Drape::Base` to `Drape::Decorator`. This is the most significant
200
+ change you'll need to upgrade your application.
201
+ [025742c](https://github.com/drapegem/drape/commit/025742cb3b295d259cf0ecf3669c24817d6f2df1)
202
+ * Added an internal Rails application for integration tests. This won't affect
203
+ your application, but we're now running a set of Cucumber tests inside of a
204
+ Rails app in both development and production mode to help ensure that we
205
+ don't make changes that break Drape.
206
+ [90a4859](https://github.com/drapegem/drape/commit/90a4859085cab158658d23d77cd3108b6037e36f)
207
+ * Add `#decorated?` method. This gives us a free RSpec matcher,
208
+ `be_decorated`.
209
+ [834a6fd](https://github.com/drapegem/drape/commit/834a6fd1f24b5646c333a04a99fe9846a58965d6)
210
+ * `#decorates` is no longer needed inside your models, and should be removed.
211
+ Decorators automatically infer the class they decorate.
212
+ [e1214d9](https://github.com/drapegem/drape/commit/e1214d97b62f2cab45227cc650029734160dcdfe)
213
+ * Decorators do not automatically come with 'finders' by default. If you'd like
214
+ to use `SomeDecorator.find(1)`, for example, simply add `#has_finders` to
215
+ the decorator to include them.
216
+ [42b6f78](https://github.com/drapegem/drape/commit/42b6f78fda4f51845dab4d35da68880f1989d178)
217
+ * To refer to the object being decorated, `#source` is now the preferred
218
+ method.
219
+ [1e84fcb](https://github.com/drapegem/drape/commit/1e84fcb4a0eab0d12f5feda6886ce1caa239cb16)
220
+ * `ActiveModel::Serialization` is included in Decorators if you've requred
221
+ `ActiveModel::Serializers`, so that decorators can be serialized.
222
+ [c4b3527](https://github.com/drapegem/drape/commit/c4b352799067506849abcbf14963ea36abda301c)
223
+ * Properly support Test::Unit.
224
+ [087e134](https://github.com/drapegem/drape/commit/087e134ed0885ec11325ffabe8ab2bebef77a33a)
225
+
226
+ And many small bug fixes and refactorings.
227
+
228
+ ## 0.x
229
+
230
+ See changes prior to version 1.0 [here](https://github.com/drapegem/drape/blob/16140fed55f57d18f8b10a0789dd1fa5b3115a8d/CHANGELOG.markdown).
@@ -0,0 +1,20 @@
1
+ Contributing to Drape
2
+ ===================
3
+
4
+ First of all, **thank you** for wanting to help and reading this!
5
+
6
+ If you have found a problem with Drape, please [check to see](https://github.com/drapegem/drape/issues) if there's already an issue and if there's not, [create a new report](https://github.com/drapegem/drape/issues/new). Please include your versions of Drape and Rails (and any other gems that are relevant to your issue, e.g. RSpec if you're having trouble in your tests).
7
+
8
+ ## Sending a pull request
9
+
10
+ Thanks again! Here's a quick how-to:
11
+
12
+ 1. [Fork the project](https://help.github.com/articles/fork-a-repo).
13
+ 2. Create a branch - `git checkout -b adding_magic`
14
+ 3. Make your changes, and add some tests!
15
+ 4. Check that the tests pass - `bundle exec rake`
16
+ 5. Commit your changes - `git commit -am "Added some magic"`
17
+ 6. Push the branch to Github - `git push origin adding_magic`
18
+ 7. Send us a [pull request](https://help.github.com/articles/using-pull-requests)!
19
+
20
+ :heart: :sparkling_heart: :heart:
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ platforms :ruby do
6
+ gem 'sqlite3'
7
+ end
8
+
9
+ platforms :jruby do
10
+ gem 'minitest', '>= 3.0'
11
+ gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0.beta2'
12
+ end
13
+
14
+ version = ENV['RAILS_VERSION'] || '5.0'
15
+
16
+ eval_gemfile File.expand_path("../gemfiles/#{version}.gemfile", __FILE__)
@@ -0,0 +1,26 @@
1
+ def rspec_guard(options = {}, &block)
2
+ options = {
3
+ version: 2,
4
+ notification: false
5
+ }.merge(options)
6
+
7
+ guard 'rspec', options, &block
8
+ end
9
+
10
+ rspec_guard spec_paths: %w(spec/drape spec/generators) do
11
+ watch(%r{^spec/.+_spec\.rb$})
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { 'spec' }
14
+ end
15
+
16
+ rspec_guard spec_paths: 'spec/integration', env: { 'RAILS_ENV' => 'development' } do
17
+ watch(%r{^spec/.+_spec\.rb$})
18
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
19
+ watch('spec/spec_helper.rb') { 'spec' }
20
+ end
21
+
22
+ rspec_guard spec_paths: 'spec/integration', env: { 'RAILS_ENV' => 'production' } do
23
+ watch(%r{^spec/.+_spec\.rb$})
24
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
25
+ watch('spec/spec_helper.rb') { 'spec' }
26
+ end
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ (The MIT License)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,592 @@
1
+ # Drape: View Models for Rails
2
+
3
+ [![TravisCI Build Status](https://travis-ci.org/MrEmelianenko/drape.svg?branch=master)](http://travis-ci.org/MrEmelianenko/drape)
4
+ [![Code Climate](https://codeclimate.com/github/MrEmelianenko/drape/badges/gpa.svg)](https://codeclimate.com/github/MrEmelianenko/drape)
5
+ [![Inline docs](http://inch-ci.org/github/MrEmelianenko/drape.svg?branch=master)](http://inch-ci.org/github/MrEmelianenko/drape)
6
+
7
+ Drape adds an object-oriented layer of presentation logic to your Rails
8
+ application.
9
+
10
+ Without Drape, this functionality might have been tangled up in procedural
11
+ helpers or adding bulk to your models. With Drape decorators, you can wrap your
12
+ models with presentation-related logic to organise - and test - this layer of
13
+ your app much more effectively.
14
+
15
+ ## Drape this is Draper?
16
+
17
+ Yes, but Drape adapted for Ruby on Rails 5.
18
+
19
+ ## Why Use a Decorator?
20
+
21
+ Imagine your application has an `Article` model. With Drape, you'd create a
22
+ corresponding `ArticleDecorator`. The decorator wraps the model, and deals
23
+ *only* with presentational concerns. In the controller, you decorate the article
24
+ before handing it off to the view:
25
+
26
+ ```ruby
27
+ # app/controllers/articles_controller.rb
28
+ def show
29
+ @article = Article.find(params[:id]).decorate
30
+ end
31
+ ```
32
+
33
+ In the view, you can use the decorator in exactly the same way as you would have
34
+ used the model. But whenever you start needing logic in the view or start
35
+ thinking about a helper method, you can implement a method on the decorator
36
+ instead.
37
+
38
+ Let's look at how you could convert an existing Rails helper to a decorator
39
+ method. You have this existing helper:
40
+
41
+ ```ruby
42
+ # app/helpers/articles_helper.rb
43
+ def publication_status(article)
44
+ if article.published?
45
+ "Published at #{article.published_at.strftime('%A, %B %e')}"
46
+ else
47
+ "Unpublished"
48
+ end
49
+ end
50
+ ```
51
+
52
+ But it makes you a little uncomfortable. `publication_status` lives in a
53
+ nebulous namespace spread across all controllers and view. Down the road, you
54
+ might want to display the publication status of a `Book`. And, of course, your
55
+ design calls for a slighly different formatting to the date for a `Book`.
56
+
57
+ Now your helper method can either switch based on the input class type (poor
58
+ Ruby style), or you break it out into two methods, `book_publication_status` and
59
+ `article_publication_status`. And keep adding methods for each publication
60
+ type...to the global helper namespace. And you'll have to remember all the names. Ick.
61
+
62
+ Ruby thrives when we use Object-Oriented style. If you didn't know Rails'
63
+ helpers existed, you'd probably imagine that your view template could feature
64
+ something like this:
65
+
66
+ ```erb
67
+ <%= @article.publication_status %>
68
+ ```
69
+
70
+ Without a decorator, you'd have to implement the `publication_status` method in
71
+ the `Article` model. That method is presentation-centric, and thus does not
72
+ belong in a model.
73
+
74
+ Instead, you implement a decorator:
75
+
76
+ ```ruby
77
+ # app/decorators/article_decorator.rb
78
+ class ArticleDecorator < Drape::Decorator
79
+ delegate_all
80
+
81
+ def publication_status
82
+ if published?
83
+ "Published at #{published_at}"
84
+ else
85
+ "Unpublished"
86
+ end
87
+ end
88
+
89
+ def published_at
90
+ object.published_at.strftime("%A, %B %e")
91
+ end
92
+ end
93
+ ```
94
+
95
+ Within the `publication_status` method we use the `published?` method. Where
96
+ does that come from? It's a method of the source `Article`, whose methods have
97
+ been made available on the decorator by the `delegate_all` call above.
98
+
99
+ You might have heard this sort of decorator called a "presenter", an "exhibit",
100
+ a "view model", or even just a "view" (in that nomenclature, what Rails calls
101
+ "views" are actually "templates"). Whatever you call it, it's a great way to
102
+ replace procedural helpers like the one above with "real" object-oriented
103
+ programming.
104
+
105
+ Decorators are the ideal place to:
106
+ * format complex data for user display
107
+ * define commonly-used representations of an object, like a `name` method that
108
+ combines `first_name` and `last_name` attributes
109
+ * mark up attributes with a little semantic HTML, like turning a `url` field
110
+ into a hyperlink
111
+
112
+ ## Installation
113
+
114
+ Add Drape to your Gemfile:
115
+
116
+ ```ruby
117
+ gem 'drape', '~> 1.0.0.beta1'
118
+ ```
119
+
120
+ And run `bundle install` within your app's directory.
121
+
122
+ If you're upgrading from a 0.x release, the major changes are outlined [in the
123
+ wiki](https://github.com/drapegem/drape/wiki/Upgrading-to-1.0).
124
+
125
+ ## Writing Decorators
126
+
127
+ Decorators inherit from `Drape::Decorator`, live in your `app/decorators`
128
+ directory, and are named for the model that they decorate:
129
+
130
+ ```ruby
131
+ # app/decorators/article_decorator.rb
132
+ class ArticleDecorator < Drape::Decorator
133
+ # ...
134
+ end
135
+ ```
136
+
137
+ ### Generators
138
+
139
+ When you have Drape installed and generate a controller...
140
+
141
+ ```
142
+ rails generate resource Article
143
+ ```
144
+
145
+ ...you'll get a decorator for free!
146
+
147
+ But if the `Article` model already exists, you can run...
148
+
149
+ ```
150
+ rails generate decorator Article
151
+ ```
152
+
153
+ ...to create the `ArticleDecorator`.
154
+
155
+ ### Accessing Helpers
156
+
157
+ Normal Rails helpers are still useful for lots of tasks. Both Rails' provided
158
+ helpers and those defined in your app can be accessed within a decorator via the `h` method:
159
+
160
+ ```ruby
161
+ class ArticleDecorator < Drape::Decorator
162
+ def emphatic
163
+ h.content_tag(:strong, "Awesome")
164
+ end
165
+ end
166
+ ```
167
+
168
+ If writing `h.` frequently is getting you down, you can add...
169
+
170
+ ```
171
+ include Drape::LazyHelpers
172
+ ```
173
+
174
+ ...at the top of your decorator class - you'll mix in a bazillion methods and
175
+ never have to type `h.` again.
176
+
177
+ (*Note*: the `capture` method is only available through `h` or `helpers`)
178
+
179
+ ### Accessing the model
180
+
181
+ When writing decorator methods you'll usually need to access the wrapped model.
182
+ While you may choose to use delegation ([covered below](#delegating-methods))
183
+ for convenience, you can always use the `object` (or its alias `model`):
184
+
185
+ ```ruby
186
+ class ArticleDecorator < Drape::Decorator
187
+ def published_at
188
+ object.published_at.strftime("%A, %B %e")
189
+ end
190
+ end
191
+ ```
192
+
193
+ ## Decorating Objects
194
+
195
+ ### Single Objects
196
+
197
+ Ok, so you've written a sweet decorator, now you're going to want to put it into
198
+ action! A simple option is to call the `decorate` method on your model:
199
+
200
+ ```ruby
201
+ @article = Article.first.decorate
202
+ ```
203
+
204
+ This infers the decorator from the object being decorated. If you want more
205
+ control - say you want to decorate a `Widget` with a more general
206
+ `ProductDecorator` - then you can instantiate a decorator directly:
207
+
208
+ ```ruby
209
+ @widget = ProductDecorator.new(Widget.first)
210
+ # or, equivalently
211
+ @widget = ProductDecorator.decorate(Widget.first)
212
+ ```
213
+
214
+ ### Collections
215
+
216
+ #### Decorating Individual Elements
217
+
218
+ If you have a collection of objects, you can decorate them all in one fell
219
+ swoop:
220
+
221
+ ```ruby
222
+ @articles = ArticleDecorator.decorate_collection(Article.all)
223
+ ```
224
+
225
+ If your collection is an ActiveRecord query, you can use this:
226
+
227
+ ```ruby
228
+ @articles = Article.popular.decorate
229
+ ```
230
+
231
+ *Note:* In Rails 3, the `.all` method returns an array and not a query. Thus you
232
+ _cannot_ use the technique of `Article.all.decorate` in Rails 3. In Rails 4,
233
+ `.all` returns a query so this techique would work fine.
234
+
235
+ #### Decorating the Collection Itself
236
+
237
+ If you want to add methods to your decorated collection (for example, for
238
+ pagination), you can subclass `Drape::CollectionDecorator`:
239
+
240
+ ```ruby
241
+ # app/decorators/articles_decorator.rb
242
+ class ArticlesDecorator < Drape::CollectionDecorator
243
+ def page_number
244
+ 42
245
+ end
246
+ end
247
+
248
+ # elsewhere...
249
+ @articles = ArticlesDecorator.new(Article.all)
250
+ # or, equivalently
251
+ @articles = ArticlesDecorator.decorate(Article.all)
252
+ ```
253
+
254
+ Drape decorates each item by calling the `decorate` method. Alternatively, you can
255
+ specify a decorator by overriding the collection decorator's `decorator_class`
256
+ method, or by passing the `:with` option to the constructor.
257
+
258
+ #### Using pagination
259
+
260
+ Some pagination gems add methods to `ActiveRecord::Relation`. For example,
261
+ [Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method
262
+ requires the collection to implement `current_page`, `total_pages`, and
263
+ `limit_value`. To expose these on a collection decorator, you can delegate to
264
+ the `object`:
265
+
266
+ ```ruby
267
+ class PaginatingDecorator < Drape::CollectionDecorator
268
+ delegate :current_page, :total_pages, :limit_value, :entry_name, :total_count, :offset_value, :last_page?
269
+ end
270
+ ```
271
+
272
+ The `delegate` method used here is the same as that added by [Active
273
+ Support](http://api.rubyonrails.org/classes/Module.html#method-i-delegate),
274
+ except that the `:to` option is not required; it defaults to `:object` when
275
+ omitted.
276
+
277
+ [will_paginate](https://github.com/mislav/will_paginate) needs the following delegations:
278
+
279
+ ```ruby
280
+ delegate :current_page, :per_page, :offset, :total_entries, :total_pages
281
+ ```
282
+
283
+ ### Decorating Associated Objects
284
+
285
+ You can automatically decorate associated models when the primary model is
286
+ decorated. Assuming an `Article` model has an associated `Author` object:
287
+
288
+ ```ruby
289
+ class ArticleDecorator < Drape::Decorator
290
+ decorates_association :author
291
+ end
292
+ ```
293
+
294
+ When `ArticleDecorator` decorates an `Article`, it will also use
295
+ `AuthorDecorator` to decorate the associated `Author`.
296
+
297
+ ### Decorated Finders
298
+
299
+ You can call `decorates_finders` in a decorator...
300
+
301
+ ```ruby
302
+ class ArticleDecorator < Drape::Decorator
303
+ decorates_finders
304
+ end
305
+ ```
306
+
307
+ ...which allows you to then call all the normal ActiveRecord-style finders on
308
+ your `ArticleDecorator` and they'll return decorated objects:
309
+
310
+ ```ruby
311
+ @article = ArticleDecorator.find(params[:id])
312
+ ```
313
+
314
+ ### When to Decorate Objects
315
+
316
+ Decorators are supposed to behave very much like the models they decorate, and
317
+ for that reason it is very tempting to just decorate your objects at the start
318
+ of your controller action and then use the decorators throughout. *Don't*.
319
+
320
+ Because decorators are designed to be consumed by the view, you should only be
321
+ accessing them there. Manipulate your models to get things ready, then decorate
322
+ at the last minute, right before you render the view. This avoids many of the
323
+ common pitfalls that arise from attempting to modify decorators (in particular,
324
+ collection decorators) after creating them.
325
+
326
+ To help you make your decorators read-only, we have the `decorates_assigned`
327
+ method in your controller. It adds a helper method that returns the decorated
328
+ version of an instance variable:
329
+
330
+ ```ruby
331
+ # app/controllers/articles_controller.rb
332
+ class ArticlesController < ApplicationController
333
+ decorates_assigned :article
334
+
335
+ def show
336
+ @article = Article.find(params[:id])
337
+ end
338
+ end
339
+ ```
340
+
341
+ The `decorates_assigned :article` bit is roughly equivalent to
342
+
343
+ ```ruby
344
+ def article
345
+ @decorated_article ||= @article.decorate
346
+ end
347
+ helper_method :article
348
+ ```
349
+
350
+ This means that you can just replace `@article` with `article` in your views and
351
+ you'll have access to an ArticleDecorator object instead. In your controller you
352
+ can continue to use the `@article` instance variable to manipulate the model -
353
+ for example, `@article.comments.build` to add a new blank comment for a form.
354
+
355
+ ## Testing
356
+
357
+ Drape supports RSpec, MiniTest::Rails, and Test::Unit, and will add the
358
+ appropriate tests when you generate a decorator.
359
+
360
+ ### RSpec
361
+
362
+ Your specs are expected to live in `spec/decorators`. If you use a different
363
+ path, you need to tag them with `type: :decorator`.
364
+
365
+ In a controller spec, you might want to check whether your instance variables
366
+ are being decorated properly. You can use the handy predicate matchers:
367
+
368
+ ```ruby
369
+ assigns(:article).should be_decorated
370
+
371
+ # or, if you want to be more specific
372
+ assigns(:article).should be_decorated_with ArticleDecorator
373
+ ```
374
+
375
+ Note that `model.decorate == model`, so your existing specs shouldn't break when
376
+ you add the decoration.
377
+
378
+ #### Spork Users
379
+
380
+ In your `Spork.prefork` block of `spec_helper.rb`, add this:
381
+
382
+ ```ruby
383
+ require 'drape/test/rspec_integration'
384
+ ```
385
+
386
+ ### Isolated Tests
387
+
388
+ In tests, Drape needs to build a view context to access helper methods. By
389
+ default, it will create an `ApplicationController` and then use its view
390
+ context. If you are speeding up your test suite by testing each component in
391
+ isolation, you can eliminate this dependency by putting the following in your
392
+ `spec_helper` or similar:
393
+
394
+ ```ruby
395
+ Drape::ViewContext.test_strategy :fast
396
+ ```
397
+
398
+ In doing so, your decorators will no longer have access to your application's
399
+ helpers. If you need to selectively include such helpers, you can pass a block:
400
+
401
+ ```ruby
402
+ Drape::ViewContext.test_strategy :fast do
403
+ include ApplicationHelper
404
+ end
405
+ ```
406
+
407
+ #### Stubbing Route Helper Functions
408
+
409
+ If you are writing isolated tests for Drape methods that call route helper
410
+ methods, you can stub them instead of needing to require Rails.
411
+
412
+ If you are using RSpec, minitest-rails, or the Test::Unit syntax of minitest,
413
+ you already have access to the Drape `helpers` in your tests since they
414
+ inherit from `Drape::TestCase`. If you are using minitest's spec syntax
415
+ without minitest-rails, you can explicitly include the Drape `helpers`:
416
+
417
+ ```ruby
418
+ describe YourDecorator do
419
+ include Drape::ViewHelpers
420
+ end
421
+ ```
422
+
423
+ Then you can stub the specific route helper functions you need using your
424
+ preferred stubbing technique (this example uses RSpec's `stub` method):
425
+
426
+ ```ruby
427
+ helpers.stub(users_path: '/users')
428
+ ```
429
+
430
+ ## Advanced usage
431
+
432
+ ### Shared Decorator Methods
433
+
434
+ You might have several decorators that share similar needs. Since decorators are
435
+ just Ruby objects, you can use any normal Ruby technique for sharing
436
+ functionality.
437
+
438
+ In Rails controllers, common functionality is organized by having all
439
+ controllers inherit from `ApplicationController`. You can apply this same
440
+ pattern to your decorators:
441
+
442
+ ```ruby
443
+ # app/decorators/application_decorator.rb
444
+ class ApplicationDecorator < Drape::Decorator
445
+ # ...
446
+ end
447
+ ```
448
+
449
+ Then modify your decorators to inherit from that `ApplicationDecorator` instead
450
+ of directly from `Drape::Decorator`:
451
+
452
+ ```ruby
453
+ class ArticleDecorator < ApplicationDecorator
454
+ # decorator methods
455
+ end
456
+ ```
457
+
458
+ ### Delegating Methods
459
+
460
+ When your decorator calls `delegate_all`, any method called on the decorator not
461
+ defined in the decorator itself will be delegated to the decorated object. This
462
+ is a very permissive interface.
463
+
464
+ If you want to strictly control which methods are called within views, you can
465
+ choose to only delegate certain methods from the decorator to the source model:
466
+
467
+ ```ruby
468
+ class ArticleDecorator < Drape::Decorator
469
+ delegate :title, :body
470
+ end
471
+ ```
472
+
473
+ We omit the `:to` argument here as it defaults to the `object` being decorated.
474
+ You could choose to delegate methods to other places like this:
475
+
476
+ ```ruby
477
+ class ArticleDecorator < Drape::Decorator
478
+ delegate :title, :body
479
+ delegate :name, :title, to: :author, prefix: true
480
+ end
481
+ ```
482
+
483
+ From your view template, assuming `@article` is decorated, you could do any of
484
+ the following:
485
+
486
+ ```ruby
487
+ @article.title # Returns the article's `.title`
488
+ @article.body # Returns the article's `.body`
489
+ @article.author_name # Returns the article's `author.name`
490
+ @article.author_title # Returns the article's `author.title`
491
+ ```
492
+
493
+ ### Adding Context
494
+
495
+ If you need to pass extra data to your decorators, you can use a `context` hash.
496
+ Methods that create decorators take it as an option, for example:
497
+
498
+ ```ruby
499
+ Article.first.decorate(context: {role: :admin})
500
+ ```
501
+
502
+ The value passed to the `:context` option is then available in the decorator
503
+ through the `context` method.
504
+
505
+ If you use `decorates_association`, the context of the parent decorator is
506
+ passed to the associated decorators. You can override this with the `:context`
507
+ option:
508
+
509
+ ```ruby
510
+ class ArticleDecorator < Drape::Decorator
511
+ decorates_association :author, context: {foo: "bar"}
512
+ end
513
+ ```
514
+
515
+ or, if you want to modify the parent's context, use a lambda that takes a hash
516
+ and returns a new hash:
517
+
518
+ ```ruby
519
+ class ArticleDecorator < Drape::Decorator
520
+ decorates_association :author,
521
+ context: ->(parent_context){ parent_context.merge(foo: "bar") }
522
+ end
523
+ ```
524
+
525
+ ### Specifying Decorators
526
+
527
+ When you're using `decorates_association`, Drape uses the `decorate` method on
528
+ the associated record(s) to perform the decoration. If you want use a specific
529
+ decorator, you can use the `:with` option:
530
+
531
+ ```ruby
532
+ class ArticleDecorator < Drape::Decorator
533
+ decorates_association :author, with: FancyPersonDecorator
534
+ end
535
+ ```
536
+
537
+ For a collection association, you can specify a `CollectionDecorator` subclass,
538
+ which is applied to the whole collection, or a singular `Decorator` subclass,
539
+ which is applied to each item individually.
540
+
541
+ ### Scoping Associations
542
+
543
+ If you want your decorated association to be ordered, limited, or otherwise
544
+ scoped, you can pass a `:scope` option to `decorates_association`, which will be
545
+ applied to the collection *before* decoration:
546
+
547
+ ```ruby
548
+ class ArticleDecorator < Drape::Decorator
549
+ decorates_association :comments, scope: :recent
550
+ end
551
+ ```
552
+
553
+ ### Proxying Class Methods
554
+
555
+ If you want to proxy class methods to the wrapped model class, including when
556
+ using `decorates_finders`, Drape needs to know the model class. By default, it
557
+ assumes that your decorators are named `SomeModelDecorator`, and then attempts
558
+ to proxy unknown class methods to `SomeModel`.
559
+
560
+ If your model name can't be inferred from your decorator name in this way, you
561
+ need to use the `decorates` method:
562
+
563
+ ```ruby
564
+ class MySpecialArticleDecorator < Drape::Decorator
565
+ decorates :article
566
+ end
567
+ ```
568
+
569
+ This is only necessary when proxying class methods.
570
+
571
+ ### Making Models Decoratable
572
+
573
+ Models get their `decorate` method from the `Drape::Decoratable` module, which
574
+ is included in `ActiveRecord::Base` and `Mongoid::Document` by default. If
575
+ you're [using another
576
+ ORM](https://github.com/drapegem/drape/wiki/Using-other-ORMs) (including
577
+ versions of Mongoid prior to 3.0), or want to decorate plain old Ruby objects,
578
+ you can include this module manually.
579
+
580
+ ## Contributors
581
+
582
+ Drape was conceived by Jeff Casimir and heavily refined by Steve Klabnik and a
583
+ great community of open source
584
+ [contributors](https://github.com/drapegem/drape/contributors).
585
+
586
+ ### Core Team
587
+
588
+ * Andrew Emelianenko (andrew@soften-it.com)
589
+ * Jeff Casimir (jeff@jumpstartlab.com)
590
+ * Steve Klabnik (steve@jumpstartlab.com)
591
+ * Vasiliy Ermolovich
592
+ * Andrew Haines