workarea 3.4.16 → 3.4.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (572) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -0
  3. metadata +10 -579
  4. data/docs/Gemfile +0 -8
  5. data/docs/Gemfile.lock +0 -130
  6. data/docs/bin/middleman +0 -29
  7. data/docs/config.rb +0 -87
  8. data/docs/config.ru +0 -7
  9. data/docs/data/articles.yml +0 -157
  10. data/docs/package.json +0 -15
  11. data/docs/source/404.html.erb +0 -13
  12. data/docs/source/articles/access-routes-in-javascript.html.md +0 -33
  13. data/docs/source/articles/add-a-content-area.html.md +0 -169
  14. data/docs/source/articles/add-a-content-block-type.html.md +0 -334
  15. data/docs/source/articles/add-a-report.html.md +0 -202
  16. data/docs/source/articles/add-css-through-the-admin-ui.html.md +0 -30
  17. data/docs/source/articles/add-javascript-through-a-manifest.html.md +0 -367
  18. data/docs/source/articles/add-javascript-through-a-view.html.md +0 -80
  19. data/docs/source/articles/add-javascript-through-the-admin-ui.html.md +0 -30
  20. data/docs/source/articles/add-metrics.html.md +0 -58
  21. data/docs/source/articles/add-or-replace-a-pricing-calculator.html.md +0 -150
  22. data/docs/source/articles/add-remove-or-change-a-mongoid-validation.html.md +0 -147
  23. data/docs/source/articles/add-remove-or-change-a-product-template.html.md +0 -142
  24. data/docs/source/articles/add-remove-sort-and-group-storefront-search-filters.html.md +0 -483
  25. data/docs/source/articles/add-stylesheets-through-a-manifest.html.md +0 -276
  26. data/docs/source/articles/add-system-content.html.md +0 -138
  27. data/docs/source/articles/analytics-overview.html.md +0 -51
  28. data/docs/source/articles/analyze-storefront-search-results.html.md +0 -261
  29. data/docs/source/articles/api-overview.html.md +0 -35
  30. data/docs/source/articles/appending.html.md +0 -506
  31. data/docs/source/articles/application-document.html.md +0 -88
  32. data/docs/source/articles/automated-javascript-testing.html.md +0 -162
  33. data/docs/source/articles/b2b-overview.html.md +0 -64
  34. data/docs/source/articles/browser-and-device-support.html.md +0 -47
  35. data/docs/source/articles/change-product-placeholder-image.html.md +0 -39
  36. data/docs/source/articles/change-storefront-search-results.html.md +0 -283
  37. data/docs/source/articles/change-the-storefront-product-pricing-ui.html.md +0 -348
  38. data/docs/source/articles/change-the-storefront-search-filters-ui.html.md +0 -103
  39. data/docs/source/articles/checkout.html.md +0 -479
  40. data/docs/source/articles/commerce-model.html.md +0 -164
  41. data/docs/source/articles/configuration-for-hosting.html.md +0 -106
  42. data/docs/source/articles/configuration.html.md +0 -406
  43. data/docs/source/articles/configure-a-payment-gateway.html.md +0 -58
  44. data/docs/source/articles/configure-asset-storage.html.md +0 -29
  45. data/docs/source/articles/configure-asset-types.html.md +0 -18
  46. data/docs/source/articles/configure-contact-form-subjects-list.html.md +0 -24
  47. data/docs/source/articles/configure-imageoptim.html.md +0 -23
  48. data/docs/source/articles/configure-locales.html.md +0 -45
  49. data/docs/source/articles/configure-logins-and-authentication.html.md +0 -42
  50. data/docs/source/articles/configure-low-inventory-threshold.html.md +0 -26
  51. data/docs/source/articles/configure-product-image-sizes-and-processing.html.md +0 -28
  52. data/docs/source/articles/content.html.md +0 -554
  53. data/docs/source/articles/contentable.html.md +0 -41
  54. data/docs/source/articles/contribute-code.html.md +0 -69
  55. data/docs/source/articles/contribute-documentation.html.md +0 -60
  56. data/docs/source/articles/create-a-custom-discount.html.md +0 -234
  57. data/docs/source/articles/create-a-new-app.html.md +0 -131
  58. data/docs/source/articles/create-a-plugin.html.md +0 -19
  59. data/docs/source/articles/create-a-style-guide.html.md +0 -71
  60. data/docs/source/articles/create-a-theme.html.md +0 -134
  61. data/docs/source/articles/css-architectural-overview.html.md +0 -89
  62. data/docs/source/articles/customize-a-helper.html.md +0 -91
  63. data/docs/source/articles/decoration.html.md +0 -415
  64. data/docs/source/articles/define-and-configure-inventory-policies.html.md +0 -107
  65. data/docs/source/articles/documentation-style-guide.html.md +0 -48
  66. data/docs/source/articles/documentation.html.md +0 -54
  67. data/docs/source/articles/domain-modeling.html.md +0 -82
  68. data/docs/source/articles/error-pages.html.md.erb +0 -95
  69. data/docs/source/articles/extension-overview.html.md +0 -152
  70. data/docs/source/articles/favicon-support.html.md +0 -112
  71. data/docs/source/articles/feature-spec-helper-stylesheet.html.md +0 -25
  72. data/docs/source/articles/featurejs-and-feature-spec-helper.html.md +0 -20
  73. data/docs/source/articles/help-and-support.html.md +0 -34
  74. data/docs/source/articles/html-fragment-caching.html.md +0 -46
  75. data/docs/source/articles/http-caching.html.md +0 -43
  76. data/docs/source/articles/i18n.html.md +0 -35
  77. data/docs/source/articles/images-flow.html.md +0 -10
  78. data/docs/source/articles/index-storefront-search-documents.html.md +0 -104
  79. data/docs/source/articles/infrastructure.html.md +0 -46
  80. data/docs/source/articles/installing.html.md +0 -61
  81. data/docs/source/articles/integrate-a-payment-gateway.html.md +0 -124
  82. data/docs/source/articles/integrate-a-web-analytics-provider.html.md +0 -35
  83. data/docs/source/articles/integrate-an-inventory-management-system.html.md +0 -88
  84. data/docs/source/articles/integrating-with-other-software.html.md +0 -59
  85. data/docs/source/articles/inventory.html.md +0 -352
  86. data/docs/source/articles/javascript-coding-standards.html.md +0 -30
  87. data/docs/source/articles/javascript-modules.html.md +0 -174
  88. data/docs/source/articles/javascript-overview.html.md +0 -62
  89. data/docs/source/articles/javascript-reference-documentation.html.md +0 -51
  90. data/docs/source/articles/javascript-templates.html.md +0 -52
  91. data/docs/source/articles/low-level-caching.html.md +0 -25
  92. data/docs/source/articles/maintain-a-plugin.html.md +0 -12
  93. data/docs/source/articles/maintenance-policy.html.md +0 -79
  94. data/docs/source/articles/navigable.html.md +0 -51
  95. data/docs/source/articles/navigating-the-code.html.md +0 -149
  96. data/docs/source/articles/navigation.html.md +0 -386
  97. data/docs/source/articles/order-life-cycle.html.md +0 -546
  98. data/docs/source/articles/order-pricing.html.md +0 -389
  99. data/docs/source/articles/orders-and-items.html.md +0 -210
  100. data/docs/source/articles/orders.html.md +0 -66
  101. data/docs/source/articles/overriding.html.md +0 -155
  102. data/docs/source/articles/overview.html.md +0 -43
  103. data/docs/source/articles/plugins-overview.html.md +0 -12
  104. data/docs/source/articles/prerequisites-and-dependencies.html.md +0 -202
  105. data/docs/source/articles/products.html.md.erb +0 -1270
  106. data/docs/source/articles/progressive-web-application-support.html.md +0 -148
  107. data/docs/source/articles/rails-asset-manifests.html.md +0 -33
  108. data/docs/source/articles/rails-asset-view-helpers.html.md +0 -25
  109. data/docs/source/articles/reading-data.html.md +0 -10
  110. data/docs/source/articles/releasable.html.md +0 -37
  111. data/docs/source/articles/report-a-bug.html.md +0 -75
  112. data/docs/source/articles/ruby-coding-standards.html.md +0 -10
  113. data/docs/source/articles/run-sidekiq-in-a-local-environment.html.md +0 -40
  114. data/docs/source/articles/searching.html.md +0 -1005
  115. data/docs/source/articles/security-policy.html.md +0 -42
  116. data/docs/source/articles/seeds.html.md +0 -345
  117. data/docs/source/articles/shipping.html.md +0 -756
  118. data/docs/source/articles/sort-and-exclude-product-options.html.md +0 -47
  119. data/docs/source/articles/storefront-search-features.html.md +0 -568
  120. data/docs/source/articles/storefront-searches.html.md +0 -126
  121. data/docs/source/articles/style-guides.html.md +0 -21
  122. data/docs/source/articles/stylesheet-coding-standards.html.md +0 -24
  123. data/docs/source/articles/stylesheets-overview.html.md +0 -67
  124. data/docs/source/articles/swappable-list-data-structure.html.md +0 -81
  125. data/docs/source/articles/system-emails.html.md +0 -102
  126. data/docs/source/articles/taggable.html.md +0 -8
  127. data/docs/source/articles/test-a-credit-card-transaction.html.md +0 -16
  128. data/docs/source/articles/test-if-a-plugin-is-installed.html.md +0 -34
  129. data/docs/source/articles/testing.html.md +0 -914
  130. data/docs/source/articles/themes-overview.html.md +0 -155
  131. data/docs/source/articles/translate-administrable-content.html.md +0 -14
  132. data/docs/source/articles/translate-javascript-content.html.md +0 -16
  133. data/docs/source/articles/translate-or-customize-message-content.html.md +0 -29
  134. data/docs/source/articles/translate-or-customize-static-content.html.md +0 -30
  135. data/docs/source/articles/use-an-existing-workarea-app.html.md +0 -108
  136. data/docs/source/articles/view-models.html.md +0 -509
  137. data/docs/source/articles/views.html.md +0 -14
  138. data/docs/source/articles/workers.html.md +0 -613
  139. data/docs/source/articles/writing-data.html.md +0 -10
  140. data/docs/source/cli.html.md +0 -163
  141. data/docs/source/favicon.ico +0 -0
  142. data/docs/source/images/3-variants-1-option.png +0 -0
  143. data/docs/source/images/3-variants-3-options.png +0 -0
  144. data/docs/source/images/3-years-primary-image.png +0 -0
  145. data/docs/source/images/404-storefront-error-page.png +0 -0
  146. data/docs/source/images/404-system-content-admin.png +0 -0
  147. data/docs/source/images/404.jpg +0 -0
  148. data/docs/source/images/5-years-primary-image.png +0 -0
  149. data/docs/source/images/activity-dashboard.png +0 -0
  150. data/docs/source/images/activity-for-object.png +0 -0
  151. data/docs/source/images/activity-ui.png +0 -0
  152. data/docs/source/images/adding-captioned-image-block-custom-icon.png +0 -0
  153. data/docs/source/images/adding-captioned-image-block-default-icon.png +0 -0
  154. data/docs/source/images/admin-alerts-ui.png +0 -0
  155. data/docs/source/images/admin-category-range-filters.png +0 -0
  156. data/docs/source/images/admin-for-3-column-hero.png +0 -0
  157. data/docs/source/images/admin-help-index.png +0 -0
  158. data/docs/source/images/admin-help-ui.png +0 -0
  159. data/docs/source/images/admin-javascript.png +0 -0
  160. data/docs/source/images/admin-notification-for-deactivated-discount.png +0 -0
  161. data/docs/source/images/admin-notifications-ui.png +0 -0
  162. data/docs/source/images/admin-product-show-page.png +0 -0
  163. data/docs/source/images/admin-products-index-page.png +0 -0
  164. data/docs/source/images/admin-range-filters.png +0 -0
  165. data/docs/source/images/admin-style-guides-navigation.png +0 -0
  166. data/docs/source/images/after-re-seeding.png +0 -0
  167. data/docs/source/images/after-seeding-localhost-3000.png +0 -0
  168. data/docs/source/images/after-seeding.png +0 -0
  169. data/docs/source/images/arrow.svg +0 -1
  170. data/docs/source/images/arrow_white.svg +0 -1
  171. data/docs/source/images/aws-resource-map.png +0 -0
  172. data/docs/source/images/backordered-until-output-on-inventory-sku-card.png +0 -0
  173. data/docs/source/images/before-seeding-localhost-3000.png +0 -0
  174. data/docs/source/images/before-seeding.png +0 -0
  175. data/docs/source/images/browsing-workarea-versions-on-the-web.png +0 -0
  176. data/docs/source/images/bulk-asset-upload-on-assets-index-page.png +0 -0
  177. data/docs/source/images/bulk-asset-upload-while-editing-content.png +0 -0
  178. data/docs/source/images/bundle-show-workarea-core.png +0 -0
  179. data/docs/source/images/bundle-show-workarea.png +0 -0
  180. data/docs/source/images/calendar-for-backordered-until-field.png +0 -0
  181. data/docs/source/images/captioned-image-block-in-storefront.png +0 -0
  182. data/docs/source/images/captioned-image-content-block-storefront-component-style-guide.png +0 -0
  183. data/docs/source/images/cart-system-content-in-admin.png +0 -0
  184. data/docs/source/images/cart-system-content-in-storefront.png +0 -0
  185. data/docs/source/images/checkout-addresses-guest.png +0 -0
  186. data/docs/source/images/checkout-addresses-user.png +0 -0
  187. data/docs/source/images/checkout-confirmation.png +0 -0
  188. data/docs/source/images/checkout-flow-0.png +0 -0
  189. data/docs/source/images/checkout-flow-1.png +0 -0
  190. data/docs/source/images/checkout-flow-2.png +0 -0
  191. data/docs/source/images/checkout-flow-3.png +0 -0
  192. data/docs/source/images/checkout-flow-4.png +0 -0
  193. data/docs/source/images/checkout-payment-guest.png +0 -0
  194. data/docs/source/images/checkout-payment-user.png +0 -0
  195. data/docs/source/images/checkout-shipping.png +0 -0
  196. data/docs/source/images/color-picker-component-admin-style-guide.png +0 -0
  197. data/docs/source/images/color-picker-component-on-content-editing-screen.png +0 -0
  198. data/docs/source/images/commerce-model-carts-orders.png +0 -0
  199. data/docs/source/images/commerce-model-order-pricing.png +0 -0
  200. data/docs/source/images/commerce-model.png +0 -0
  201. data/docs/source/images/configuring-an-index-pattern-in-kibana.png +0 -0
  202. data/docs/source/images/content-block-presets.png +0 -0
  203. data/docs/source/images/content-search-customization.png +0 -0
  204. data/docs/source/images/country-with-region-data-in-address-form.png +0 -0
  205. data/docs/source/images/country-without-region-data-in-address-form.png +0 -0
  206. data/docs/source/images/create-content-block-preset-ui.png +0 -0
  207. data/docs/source/images/credit-card-icons.png +0 -0
  208. data/docs/source/images/css-added-through-admin.png +0 -0
  209. data/docs/source/images/css-admin-ui.png +0 -0
  210. data/docs/source/images/current-configuration-shown-in-admin-settings.png +0 -0
  211. data/docs/source/images/customer-impersonation-in-admin.png +0 -0
  212. data/docs/source/images/customer-impersonation-in-store-front.png +0 -0
  213. data/docs/source/images/date-filter-same-day.png +0 -0
  214. data/docs/source/images/developer-toolbar-in-store-front.png +0 -0
  215. data/docs/source/images/discounts-sorted-by-most-redeemed.png +0 -0
  216. data/docs/source/images/edit-help-article.png +0 -0
  217. data/docs/source/images/editing-content-for-search-customization.png +0 -0
  218. data/docs/source/images/editing-dynamic-captioned-image-block.png +0 -0
  219. data/docs/source/images/editing-product-fields-in-the-admin.png +0 -0
  220. data/docs/source/images/editing-search-system-content.png +0 -0
  221. data/docs/source/images/editing-static-captioned-image-block-custom-icon.png +0 -0
  222. data/docs/source/images/editing-static-captioned-image-block-default-icon.png +0 -0
  223. data/docs/source/images/external.svg +0 -1
  224. data/docs/source/images/favicon_16.png +0 -0
  225. data/docs/source/images/favicon_180.png +0 -0
  226. data/docs/source/images/favicon_32.png +0 -0
  227. data/docs/source/images/filters-all.png +0 -0
  228. data/docs/source/images/filters-control.png +0 -0
  229. data/docs/source/images/filters-custom.png +0 -0
  230. data/docs/source/images/filters-groups.png +0 -0
  231. data/docs/source/images/filters-material.png +0 -0
  232. data/docs/source/images/filters-omitted.png +0 -0
  233. data/docs/source/images/filters-pinned.png +0 -0
  234. data/docs/source/images/filters-range.png +0 -0
  235. data/docs/source/images/filters-sorted.png +0 -0
  236. data/docs/source/images/filters-wrapping-to-second-line-in-admin.png +0 -0
  237. data/docs/source/images/generic-product-template-images-no-options-selected.png +0 -0
  238. data/docs/source/images/generic-product-template-images-options-selected.png +0 -0
  239. data/docs/source/images/generic-template.png +0 -0
  240. data/docs/source/images/hosting.svg +0 -1
  241. data/docs/source/images/image-group-content-block-in-storefront.png +0 -0
  242. data/docs/source/images/images.svg +0 -1
  243. data/docs/source/images/import-export-screenshot.png +0 -0
  244. data/docs/source/images/invalid-display.png +0 -0
  245. data/docs/source/images/itcss.png +0 -0
  246. data/docs/source/images/kibana-dev-tools-console.png +0 -0
  247. data/docs/source/images/layout-content-admin-with-2-areas.png +0 -0
  248. data/docs/source/images/layout-content-admin-with-3-areas.png +0 -0
  249. data/docs/source/images/link-to-search-system-content.png +0 -0
  250. data/docs/source/images/logo.svg +0 -1
  251. data/docs/source/images/menu.svg +0 -2
  252. data/docs/source/images/mongo-replica-set.svg +0 -1
  253. data/docs/source/images/multi-column-hero-blocks.png +0 -0
  254. data/docs/source/images/option-selects-product-template-images-options-selected.png +0 -0
  255. data/docs/source/images/option-selects-template.png +0 -0
  256. data/docs/source/images/option-thumbnails-template.png +0 -0
  257. data/docs/source/images/order-item-total-price-diagram.png +0 -0
  258. data/docs/source/images/order-pricing-cart-example.png +0 -0
  259. data/docs/source/images/order-pricing-example-adjustments.png +0 -0
  260. data/docs/source/images/order-pricing-example-totals.png +0 -0
  261. data/docs/source/images/order-pricing-placed-order-example.png +0 -0
  262. data/docs/source/images/order-shipping-total-diagram.png +0 -0
  263. data/docs/source/images/order-show-with-multiple-tenders.png +0 -0
  264. data/docs/source/images/order-subtotal-price-diagram.png +0 -0
  265. data/docs/source/images/order-tax-total-diagram.png +0 -0
  266. data/docs/source/images/order-total-price-diagram.png +0 -0
  267. data/docs/source/images/order-total-value-diagram.png +0 -0
  268. data/docs/source/images/orders-dashboard-links.png +0 -0
  269. data/docs/source/images/oval.svg +0 -1
  270. data/docs/source/images/payment-icon-storefront-style-guide.png +0 -0
  271. data/docs/source/images/people-dashboard-links.png +0 -0
  272. data/docs/source/images/price-adjustments-diagram.png +0 -0
  273. data/docs/source/images/price-display-no-options.png +0 -0
  274. data/docs/source/images/price-display-options-selected.png +0 -0
  275. data/docs/source/images/pricing-calculators-diagram.png +0 -0
  276. data/docs/source/images/product-list-content-block-admin.png +0 -0
  277. data/docs/source/images/product-list-content-block-in-store-front.png +0 -0
  278. data/docs/source/images/promo-products-excluded-autocomplete-results-after.png +0 -0
  279. data/docs/source/images/promo-products-excluded-featured-category-results-after.png +0 -0
  280. data/docs/source/images/promo-products-excluded-recommendations-results-after.png +0 -0
  281. data/docs/source/images/promo-products-excluded-search-category-results-after.png +0 -0
  282. data/docs/source/images/promo-products-excluded-search-results-after.png +0 -0
  283. data/docs/source/images/promo-products-included-autocomplete-results-before.png +0 -0
  284. data/docs/source/images/promo-products-included-featured-category-results-before.png +0 -0
  285. data/docs/source/images/promo-products-included-recommendations-results-before.png +0 -0
  286. data/docs/source/images/promo-products-included-search-category-results-before.png +0 -0
  287. data/docs/source/images/promo-products-included-search-results-before.png +0 -0
  288. data/docs/source/images/rails-version-constraint.png +0 -0
  289. data/docs/source/images/re-enable-discount.png +0 -0
  290. data/docs/source/images/reading-data.svg +0 -1
  291. data/docs/source/images/readme-hero.png +0 -0
  292. data/docs/source/images/redesigned-customized-sort-for-search-results.png +0 -0
  293. data/docs/source/images/reviews-summary-above-share-buttons.png +0 -0
  294. data/docs/source/images/reviews-summary-below-product-name.png +0 -0
  295. data/docs/source/images/reviews-summary-below-share-buttons.png +0 -0
  296. data/docs/source/images/reviews-summary-removed.png +0 -0
  297. data/docs/source/images/rsa-fingerprint-for-stash.png +0 -0
  298. data/docs/source/images/ruby-version-constraint.png +0 -0
  299. data/docs/source/images/script-tag-added-through-admin.png +0 -0
  300. data/docs/source/images/search-analysis-admin-alternate-rendering.png +0 -0
  301. data/docs/source/images/search-analysis-admin.png +0 -0
  302. data/docs/source/images/search-quality-report.png +0 -0
  303. data/docs/source/images/search.svg +0 -1
  304. data/docs/source/images/searching-for-cart-system-content-in-admin.png +0 -0
  305. data/docs/source/images/searching-for-layout-system-content-in-admin.png +0 -0
  306. data/docs/source/images/seeded-admin.png +0 -0
  307. data/docs/source/images/seeds-from-plugins.png +0 -0
  308. data/docs/source/images/seo-metadata-automation-ui.png +0 -0
  309. data/docs/source/images/show-password-button.png +0 -0
  310. data/docs/source/images/storefront-autocomplete.png +0 -0
  311. data/docs/source/images/storefront-category-summary-content-block.png +0 -0
  312. data/docs/source/images/storefront-category.png +0 -0
  313. data/docs/source/images/storefront-product-after-overriding.png +0 -0
  314. data/docs/source/images/storefront-product-before-overriding.png +0 -0
  315. data/docs/source/images/storefront-product-browse-page.png +0 -0
  316. data/docs/source/images/storefront-product-recommendations.png +0 -0
  317. data/docs/source/images/storefront-product-show-page.png +0 -0
  318. data/docs/source/images/storefront-requests-and-search-requests.png +0 -0
  319. data/docs/source/images/storefront-search-request-handling.png +0 -0
  320. data/docs/source/images/storefront-search-response-creation.png +0 -0
  321. data/docs/source/images/storefront-search.png +0 -0
  322. data/docs/source/images/storefront-style-guides-navigation.png +0 -0
  323. data/docs/source/images/styles.css +0 -3
  324. data/docs/source/images/tax-categories-ui.png +0 -0
  325. data/docs/source/images/tax-rates-ui.png +0 -0
  326. data/docs/source/images/unpurchasable-product.png +0 -0
  327. data/docs/source/images/url-redirects-filtering.png +0 -0
  328. data/docs/source/images/utility-nav-area-in-admin.png +0 -0
  329. data/docs/source/images/utility-nav-area-in-storefront.png +0 -0
  330. data/docs/source/images/validation-message-in-storefront.png +0 -0
  331. data/docs/source/images/view-model-interface.png +0 -0
  332. data/docs/source/images/viewing-workarea-version-in-source.png +0 -0
  333. data/docs/source/images/workarea.svg +0 -1
  334. data/docs/source/images/worst-performing-searches-on-results-customization-page.png +0 -0
  335. data/docs/source/images/writing-data.svg +0 -1
  336. data/docs/source/index.html.erb +0 -166
  337. data/docs/source/javascripts/jquery.js +0 -2
  338. data/docs/source/javascripts/lunr.js +0 -7
  339. data/docs/source/javascripts/site.js +0 -299
  340. data/docs/source/javascripts/vendor/highlight.pack.js +0 -2
  341. data/docs/source/layouts/article.erb +0 -106
  342. data/docs/source/layouts/bare.erb +0 -46
  343. data/docs/source/layouts/layout.erb +0 -43
  344. data/docs/source/release-notes/workarea-3-0-0.html.md +0 -146
  345. data/docs/source/release-notes/workarea-3-0-1.html.md +0 -161
  346. data/docs/source/release-notes/workarea-3-0-10.html.md +0 -39
  347. data/docs/source/release-notes/workarea-3-0-11.html.md +0 -277
  348. data/docs/source/release-notes/workarea-3-0-12.html.md +0 -14
  349. data/docs/source/release-notes/workarea-3-0-13.html.md +0 -153
  350. data/docs/source/release-notes/workarea-3-0-14.html.md +0 -93
  351. data/docs/source/release-notes/workarea-3-0-15.html.md +0 -107
  352. data/docs/source/release-notes/workarea-3-0-16.html.md +0 -36
  353. data/docs/source/release-notes/workarea-3-0-17.html.md +0 -141
  354. data/docs/source/release-notes/workarea-3-0-18.html.md +0 -123
  355. data/docs/source/release-notes/workarea-3-0-19.html.md +0 -160
  356. data/docs/source/release-notes/workarea-3-0-2.html.md +0 -222
  357. data/docs/source/release-notes/workarea-3-0-20.html.md +0 -95
  358. data/docs/source/release-notes/workarea-3-0-21.html.md +0 -168
  359. data/docs/source/release-notes/workarea-3-0-22.html.md +0 -268
  360. data/docs/source/release-notes/workarea-3-0-23.html.md +0 -173
  361. data/docs/source/release-notes/workarea-3-0-24.html.md +0 -19
  362. data/docs/source/release-notes/workarea-3-0-25.html.md +0 -26
  363. data/docs/source/release-notes/workarea-3-0-26.html.md +0 -199
  364. data/docs/source/release-notes/workarea-3-0-27.html.md +0 -113
  365. data/docs/source/release-notes/workarea-3-0-28.html.md +0 -39
  366. data/docs/source/release-notes/workarea-3-0-29.html.md +0 -73
  367. data/docs/source/release-notes/workarea-3-0-3.html.md +0 -35
  368. data/docs/source/release-notes/workarea-3-0-30.html.md +0 -186
  369. data/docs/source/release-notes/workarea-3-0-31.html.md +0 -125
  370. data/docs/source/release-notes/workarea-3-0-32.html.md +0 -73
  371. data/docs/source/release-notes/workarea-3-0-33.html.md +0 -137
  372. data/docs/source/release-notes/workarea-3-0-34.html.md +0 -203
  373. data/docs/source/release-notes/workarea-3-0-35.html.md +0 -205
  374. data/docs/source/release-notes/workarea-3-0-36.html.md +0 -105
  375. data/docs/source/release-notes/workarea-3-0-37.html.md +0 -144
  376. data/docs/source/release-notes/workarea-3-0-38.html.md +0 -73
  377. data/docs/source/release-notes/workarea-3-0-39.html.md +0 -77
  378. data/docs/source/release-notes/workarea-3-0-4.html.md +0 -14
  379. data/docs/source/release-notes/workarea-3-0-40.html.md +0 -130
  380. data/docs/source/release-notes/workarea-3-0-41.html.md +0 -70
  381. data/docs/source/release-notes/workarea-3-0-42.html.md +0 -52
  382. data/docs/source/release-notes/workarea-3-0-43.html.md +0 -72
  383. data/docs/source/release-notes/workarea-3-0-44.html.md +0 -93
  384. data/docs/source/release-notes/workarea-3-0-45.html.md +0 -61
  385. data/docs/source/release-notes/workarea-3-0-46.html.md +0 -171
  386. data/docs/source/release-notes/workarea-3-0-47.html.md +0 -130
  387. data/docs/source/release-notes/workarea-3-0-48.html.md +0 -160
  388. data/docs/source/release-notes/workarea-3-0-49.html.md +0 -28
  389. data/docs/source/release-notes/workarea-3-0-5.html.md +0 -225
  390. data/docs/source/release-notes/workarea-3-0-50.html.md +0 -74
  391. data/docs/source/release-notes/workarea-3-0-51.html.md +0 -61
  392. data/docs/source/release-notes/workarea-3-0-52.html.md +0 -76
  393. data/docs/source/release-notes/workarea-3-0-53.html.md +0 -126
  394. data/docs/source/release-notes/workarea-3-0-54.html.md +0 -112
  395. data/docs/source/release-notes/workarea-3-0-55.html.md +0 -105
  396. data/docs/source/release-notes/workarea-3-0-56.html.md +0 -56
  397. data/docs/source/release-notes/workarea-3-0-57.html.md +0 -82
  398. data/docs/source/release-notes/workarea-3-0-58.html.md +0 -153
  399. data/docs/source/release-notes/workarea-3-0-59.html.md +0 -78
  400. data/docs/source/release-notes/workarea-3-0-6.html.md +0 -165
  401. data/docs/source/release-notes/workarea-3-0-60.html.md +0 -43
  402. data/docs/source/release-notes/workarea-3-0-61.html.md +0 -46
  403. data/docs/source/release-notes/workarea-3-0-62.html.md +0 -23
  404. data/docs/source/release-notes/workarea-3-0-63.html.md +0 -25
  405. data/docs/source/release-notes/workarea-3-0-64.html.md +0 -25
  406. data/docs/source/release-notes/workarea-3-0-65.html.md +0 -37
  407. data/docs/source/release-notes/workarea-3-0-7.html.md +0 -207
  408. data/docs/source/release-notes/workarea-3-0-8.html.md +0 -337
  409. data/docs/source/release-notes/workarea-3-0-9.html.md +0 -196
  410. data/docs/source/release-notes/workarea-3-1-0.html.md +0 -414
  411. data/docs/source/release-notes/workarea-3-1-1.html.md +0 -139
  412. data/docs/source/release-notes/workarea-3-1-10.html.md +0 -19
  413. data/docs/source/release-notes/workarea-3-1-11.html.md +0 -27
  414. data/docs/source/release-notes/workarea-3-1-12.html.md +0 -216
  415. data/docs/source/release-notes/workarea-3-1-13.html.md +0 -113
  416. data/docs/source/release-notes/workarea-3-1-14.html.md +0 -39
  417. data/docs/source/release-notes/workarea-3-1-15.html.md +0 -107
  418. data/docs/source/release-notes/workarea-3-1-16.html.md +0 -188
  419. data/docs/source/release-notes/workarea-3-1-17.html.md +0 -141
  420. data/docs/source/release-notes/workarea-3-1-18.html.md +0 -73
  421. data/docs/source/release-notes/workarea-3-1-19.html.md +0 -137
  422. data/docs/source/release-notes/workarea-3-1-2.html.md +0 -55
  423. data/docs/source/release-notes/workarea-3-1-20.html.md +0 -203
  424. data/docs/source/release-notes/workarea-3-1-21.html.md +0 -205
  425. data/docs/source/release-notes/workarea-3-1-22.html.md +0 -121
  426. data/docs/source/release-notes/workarea-3-1-23.html.md +0 -144
  427. data/docs/source/release-notes/workarea-3-1-24.html.md +0 -94
  428. data/docs/source/release-notes/workarea-3-1-25.html.md +0 -77
  429. data/docs/source/release-notes/workarea-3-1-26.html.md +0 -130
  430. data/docs/source/release-notes/workarea-3-1-27.html.md +0 -70
  431. data/docs/source/release-notes/workarea-3-1-28.html.md +0 -52
  432. data/docs/source/release-notes/workarea-3-1-29.html.md +0 -44
  433. data/docs/source/release-notes/workarea-3-1-3.html.md +0 -185
  434. data/docs/source/release-notes/workarea-3-1-30.html.md +0 -72
  435. data/docs/source/release-notes/workarea-3-1-31.html.md +0 -93
  436. data/docs/source/release-notes/workarea-3-1-32.html.md +0 -61
  437. data/docs/source/release-notes/workarea-3-1-33.html.md +0 -171
  438. data/docs/source/release-notes/workarea-3-1-34.html.md +0 -130
  439. data/docs/source/release-notes/workarea-3-1-35.html.md +0 -179
  440. data/docs/source/release-notes/workarea-3-1-36.html.md +0 -28
  441. data/docs/source/release-notes/workarea-3-1-37.html.md +0 -74
  442. data/docs/source/release-notes/workarea-3-1-38.html.md +0 -61
  443. data/docs/source/release-notes/workarea-3-1-39.html.md +0 -96
  444. data/docs/source/release-notes/workarea-3-1-4.html.md +0 -148
  445. data/docs/source/release-notes/workarea-3-1-40.html.md +0 -126
  446. data/docs/source/release-notes/workarea-3-1-41.html.md +0 -128
  447. data/docs/source/release-notes/workarea-3-1-42.html.md +0 -105
  448. data/docs/source/release-notes/workarea-3-1-43.html.md +0 -37
  449. data/docs/source/release-notes/workarea-3-1-44.html.md +0 -82
  450. data/docs/source/release-notes/workarea-3-1-45.html.md +0 -153
  451. data/docs/source/release-notes/workarea-3-1-46.html.md +0 -91
  452. data/docs/source/release-notes/workarea-3-1-47.html.md +0 -65
  453. data/docs/source/release-notes/workarea-3-1-48.html.md +0 -46
  454. data/docs/source/release-notes/workarea-3-1-49.html.md +0 -23
  455. data/docs/source/release-notes/workarea-3-1-5.html.md +0 -169
  456. data/docs/source/release-notes/workarea-3-1-50.html.md +0 -42
  457. data/docs/source/release-notes/workarea-3-1-51.html.md +0 -25
  458. data/docs/source/release-notes/workarea-3-1-52.html.md +0 -57
  459. data/docs/source/release-notes/workarea-3-1-6.html.md +0 -117
  460. data/docs/source/release-notes/workarea-3-1-7.html.md +0 -176
  461. data/docs/source/release-notes/workarea-3-1-8.html.md +0 -283
  462. data/docs/source/release-notes/workarea-3-1-9.html.md +0 -212
  463. data/docs/source/release-notes/workarea-3-2-0.html.md +0 -1705
  464. data/docs/source/release-notes/workarea-3-2-1.html.md +0 -216
  465. data/docs/source/release-notes/workarea-3-2-10.html.md +0 -237
  466. data/docs/source/release-notes/workarea-3-2-11.html.md +0 -121
  467. data/docs/source/release-notes/workarea-3-2-12.html.md +0 -145
  468. data/docs/source/release-notes/workarea-3-2-13.html.md +0 -138
  469. data/docs/source/release-notes/workarea-3-2-14.html.md +0 -77
  470. data/docs/source/release-notes/workarea-3-2-15.html.md +0 -130
  471. data/docs/source/release-notes/workarea-3-2-16.html.md +0 -111
  472. data/docs/source/release-notes/workarea-3-2-17.html.md +0 -52
  473. data/docs/source/release-notes/workarea-3-2-18.html.md +0 -44
  474. data/docs/source/release-notes/workarea-3-2-19.html.md +0 -72
  475. data/docs/source/release-notes/workarea-3-2-2.html.md +0 -145
  476. data/docs/source/release-notes/workarea-3-2-20.html.md +0 -93
  477. data/docs/source/release-notes/workarea-3-2-21.html.md +0 -61
  478. data/docs/source/release-notes/workarea-3-2-22.html.md +0 -154
  479. data/docs/source/release-notes/workarea-3-2-23.html.md +0 -130
  480. data/docs/source/release-notes/workarea-3-2-24.html.md +0 -200
  481. data/docs/source/release-notes/workarea-3-2-25.html.md +0 -28
  482. data/docs/source/release-notes/workarea-3-2-26.html.md +0 -94
  483. data/docs/source/release-notes/workarea-3-2-27.html.md +0 -61
  484. data/docs/source/release-notes/workarea-3-2-28.html.md +0 -96
  485. data/docs/source/release-notes/workarea-3-2-29.html.md +0 -126
  486. data/docs/source/release-notes/workarea-3-2-30.html.md +0 -112
  487. data/docs/source/release-notes/workarea-3-2-31.html.md +0 -105
  488. data/docs/source/release-notes/workarea-3-2-32.html.md +0 -56
  489. data/docs/source/release-notes/workarea-3-2-33.html.md +0 -82
  490. data/docs/source/release-notes/workarea-3-2-34.html.md +0 -153
  491. data/docs/source/release-notes/workarea-3-2-35.html.md +0 -91
  492. data/docs/source/release-notes/workarea-3-2-36.html.md +0 -118
  493. data/docs/source/release-notes/workarea-3-2-37.html.md +0 -46
  494. data/docs/source/release-notes/workarea-3-2-38.html.md +0 -23
  495. data/docs/source/release-notes/workarea-3-2-39.html.md +0 -42
  496. data/docs/source/release-notes/workarea-3-2-4.html.md +0 -109
  497. data/docs/source/release-notes/workarea-3-2-40.html.md +0 -25
  498. data/docs/source/release-notes/workarea-3-2-41.html.md +0 -90
  499. data/docs/source/release-notes/workarea-3-2-5.html.md +0 -186
  500. data/docs/source/release-notes/workarea-3-2-6.html.md +0 -173
  501. data/docs/source/release-notes/workarea-3-2-7.html.md +0 -89
  502. data/docs/source/release-notes/workarea-3-2-8.html.md +0 -137
  503. data/docs/source/release-notes/workarea-3-2-9.html.md +0 -219
  504. data/docs/source/release-notes/workarea-3-3-0.html.md +0 -1272
  505. data/docs/source/release-notes/workarea-3-3-1.html.md +0 -324
  506. data/docs/source/release-notes/workarea-3-3-10.html.md +0 -69
  507. data/docs/source/release-notes/workarea-3-3-11.html.md +0 -72
  508. data/docs/source/release-notes/workarea-3-3-12.html.md +0 -136
  509. data/docs/source/release-notes/workarea-3-3-13.html.md +0 -61
  510. data/docs/source/release-notes/workarea-3-3-14.html.md +0 -196
  511. data/docs/source/release-notes/workarea-3-3-15.html.md +0 -167
  512. data/docs/source/release-notes/workarea-3-3-16.html.md +0 -234
  513. data/docs/source/release-notes/workarea-3-3-17.html.md +0 -82
  514. data/docs/source/release-notes/workarea-3-3-18.html.md +0 -165
  515. data/docs/source/release-notes/workarea-3-3-19.html.md +0 -106
  516. data/docs/source/release-notes/workarea-3-3-2.html.md +0 -72
  517. data/docs/source/release-notes/workarea-3-3-20.html.md +0 -116
  518. data/docs/source/release-notes/workarea-3-3-21.html.md +0 -228
  519. data/docs/source/release-notes/workarea-3-3-22.html.md +0 -125
  520. data/docs/source/release-notes/workarea-3-3-23.html.md +0 -154
  521. data/docs/source/release-notes/workarea-3-3-24.html.md +0 -70
  522. data/docs/source/release-notes/workarea-3-3-25.html.md +0 -114
  523. data/docs/source/release-notes/workarea-3-3-26.html.md +0 -260
  524. data/docs/source/release-notes/workarea-3-3-27.html.md +0 -138
  525. data/docs/source/release-notes/workarea-3-3-28.html.md +0 -147
  526. data/docs/source/release-notes/workarea-3-3-29.html.md +0 -63
  527. data/docs/source/release-notes/workarea-3-3-3.html.md +0 -153
  528. data/docs/source/release-notes/workarea-3-3-30.html.md +0 -102
  529. data/docs/source/release-notes/workarea-3-3-31.html.md +0 -57
  530. data/docs/source/release-notes/workarea-3-3-32.html.md +0 -44
  531. data/docs/source/release-notes/workarea-3-3-33.html.md +0 -114
  532. data/docs/source/release-notes/workarea-3-3-34.html.md +0 -29
  533. data/docs/source/release-notes/workarea-3-3-4.html.md +0 -332
  534. data/docs/source/release-notes/workarea-3-3-5.html.md +0 -242
  535. data/docs/source/release-notes/workarea-3-3-6.html.md +0 -100
  536. data/docs/source/release-notes/workarea-3-3-7.html.md +0 -148
  537. data/docs/source/release-notes/workarea-3-3-8.html.md +0 -163
  538. data/docs/source/release-notes/workarea-3-3-9.html.md +0 -93
  539. data/docs/source/release-notes/workarea-3-4-0.html.md +0 -580
  540. data/docs/source/release-notes/workarea-3-4-1.html.md +0 -150
  541. data/docs/source/release-notes/workarea-3-4-10.html.md +0 -72
  542. data/docs/source/release-notes/workarea-3-4-11.html.md +0 -60
  543. data/docs/source/release-notes/workarea-3-4-12.html.md +0 -155
  544. data/docs/source/release-notes/workarea-3-4-15.html.md +0 -100
  545. data/docs/source/release-notes/workarea-3-4-16.html.md +0 -88
  546. data/docs/source/release-notes/workarea-3-4-2.html.md +0 -188
  547. data/docs/source/release-notes/workarea-3-4-3.html.md +0 -136
  548. data/docs/source/release-notes/workarea-3-4-4.html.md +0 -114
  549. data/docs/source/release-notes/workarea-3-4-5.html.md +0 -275
  550. data/docs/source/release-notes/workarea-3-4-6.html.md +0 -169
  551. data/docs/source/release-notes/workarea-3-4-7.html.md +0 -162
  552. data/docs/source/release-notes/workarea-3-4-8.html.md +0 -95
  553. data/docs/source/release-notes/workarea-3-4-9.html.md +0 -135
  554. data/docs/source/release-notes.html.md +0 -261
  555. data/docs/source/search.html.erb +0 -34
  556. data/docs/source/shared/_header.erb +0 -61
  557. data/docs/source/shared/_svgs.erb +0 -17
  558. data/docs/source/style_guide/index.html.erb +0 -382
  559. data/docs/source/stylesheets/_base.scss +0 -125
  560. data/docs/source/stylesheets/_components.scss +0 -669
  561. data/docs/source/stylesheets/_helpers.scss +0 -10
  562. data/docs/source/stylesheets/_opinions.scss +0 -42
  563. data/docs/source/stylesheets/_settings.scss +0 -56
  564. data/docs/source/stylesheets/_typography.scss +0 -119
  565. data/docs/source/stylesheets/site.css.scss +0 -14
  566. data/docs/source/stylesheets/vendor/_avalanche.scss +0 -328
  567. data/docs/source/stylesheets/vendor/_normalize.scss +0 -341
  568. data/docs/source/stylesheets/vendor/highlight/_tomorrow_night_blue.scss +0 -75
  569. data/docs/source/upgrade-guides/workarea-3-4-0.html.md +0 -152
  570. data/docs/source/upgrade-guides.html.md +0 -18
  571. data/docs/workarea_renderer.rb +0 -8
  572. data/docs/yarn.lock +0 -2522
@@ -1,509 +0,0 @@
1
- ---
2
- title: View Models
3
- excerpt: Workarea adds a view model layer to the standard controller/model/view/helper architecture provided by Rails. View models are concerned with database reads and logic related to those reads. Each view model instance "wraps" a model instance in order to
4
- ---
5
-
6
- # View Models
7
-
8
- Workarea adds a <dfn>view model</dfn> layer to the standard controller/model/view/helper architecture provided by Rails. View models are concerned with database reads and logic related to those reads. Each view model instance "wraps" a model instance in order to modify and augment it before presenting it within a particular UI, such as the Admin or Store Front.
9
-
10
- Review the Storefront's categories controller, shown below in its entirety:
11
-
12
- workarea-storefront/app/controllers/workarea/storefront/categories\_controller.rb:
13
-
14
- ```
15
- module Workarea
16
- class Storefront::CategoriesController < Storefront::ApplicationController
17
- before_filter :cache_page
18
-
19
- def show
20
- model = Catalog::Category.find_by_slug(params[:id])
21
- @category = Storefront::CategoryViewModel.new(model, view_model_options)
22
- end
23
- end
24
- end
25
- ```
26
-
27
- The `show` method in this controller resembles the simple controller actions shown in beginning Rails tutorials. Controller actions in such tutorials use the params to get a model instance, store it in an instance variable that will be accessible in the view, and finish by implicitly rendering the view based on naming convention. The Workarea controller above is identical, with one exception. The model is "wrapped" with a view model, so `@category` refers to a view model instance rather than a model instance.
28
-
29
- In the view, the view model instance provides the single interface for all the data and logic needed to present the model within this context. In the view excerpt below, you can see how the view model instance stored in `@category` provides the data and logic needed to present a category within the Store Front.
30
-
31
- workarea-storefront/app/views/workarea/storefront/categories/show.html.haml:
32
-
33
- ```
34
- / ...
35
-
36
- - cache @category.cache_key, expires_in: 1.hour do
37
- .view{ data: { analytics: category_view_analytics_data(@category).to_json } }
38
-
39
- %h1= @category.name
40
-
41
- - if @category.content_for(:area_1).present?
42
- = render_content_blocks(@category.content_for(:area_1))
43
-
44
- - unless @category.products.any?
45
- %p
46
- = t('workarea.storefront.products.none_found')
47
- - if @category.has_filters?
48
- = link_to t('workarea.storefront.products.reset_filters'), category_path(@category)
49
- / ...
50
- ```
51
-
52
- ## Philosophy
53
-
54
- Before looking more closely at Workarea's view model implementation, I'd like to explain _why_ view models are used within the platform.
55
-
56
- Within Workarea, view models are used to:
57
-
58
- - read across bounded contexts,
59
- - present a model within a UI,
60
- - keep controllers lean,
61
- - and provide a single interface to the view, reducing view logic.
62
-
63
- Let's look at each of these in turn.
64
-
65
- ### Read Across Bounded Contexts
66
-
67
- As explained in the [Domain Modeling](domain-modeling.html) guide, Workarea's models are organized into bounded contexts. The models within each bounded context address a particular problem set, and they do not cross their boundaries into other contexts.
68
-
69
- For example, orders, users, payments, shipments, and fulfullments are sufficiently complicated that each is encapsulated into its own context. However, presenting an order to an end user requires reading from all of these contexts. **View models may read across bounded contexts**.
70
-
71
- Take a look at the following excerpt from the Store Front's order view model:
72
-
73
- workarea-storefront/app/view\_models/workarea/storefront/order\_view\_model.rb:
74
-
75
- ```
76
- module Workarea
77
- module Storefront
78
- class OrderViewModel < ApplicationViewModel
79
- # ...
80
-
81
- delegate :tenders, :credit_card, :credit_card?,
82
- :store_credit?, :store_credit,
83
- to: :payment
84
-
85
- # ...
86
-
87
- delegate :shipping_method, to: :shipment, allow_nil: true
88
-
89
- def user
90
- @user ||= User.find(model.user_id) if model.user_id.present?
91
- end
92
-
93
- # ...
94
-
95
- private
96
-
97
- def payment
98
- @payment ||= Payment.find_or_initialize_by(id: number)
99
- end
100
-
101
- def shipment
102
- @shipment ||= Shipping::Shipment.find_by_number(number)
103
- end
104
-
105
- def fulfillment
106
- @fulfillment ||= Fulfillment.find_or_initialize_by(id: number)
107
- end
108
-
109
- # ...
110
- end
111
- end
112
- end
113
- ```
114
-
115
- The `user`, `payment`, `shipment`, and `fulfillment` methods clearly reach across domain boundaries to retrieve the necessary data from models within other contexts. You can also see other methods being delegated to the payment and the shipment. Data reads that cross domain boundaries in this fashion are unique to view models. In this way, **view models keep models decoupled**.
116
-
117
- ### Present a Model Within a UI
118
-
119
- The view model above is responsible for presenting an order in the Store Front. In order to do this, the view model modifies and augments the state and behavior of the order model instance that it wraps. It does so to format the data for display within the Store Front.
120
-
121
- For example, when presenting an order in the Store Front, the store credit amount must always be available as a non-`nil` value. The `store_credit_amount` method in the Store Front order view model takes care of this:
122
-
123
- workarea-storefront/app/view\_models/workarea/storefront/order\_view\_model.rb:
124
-
125
- ```
126
- module Workarea
127
- module Storefront
128
- class OrderViewModel < ApplicationViewModel
129
- # ...
130
-
131
- def store_credit_amount
132
- if store_credit.present?
133
- store_credit.amount
134
- else
135
- 0.to_m
136
- end
137
- end
138
-
139
- # ...
140
- end
141
- end
142
- end
143
- ```
144
-
145
- Additionally, to display a full name, the Storefront _and_ Admin order view models both implement `full_name`:
146
-
147
- workarea-admin/app/view\_models/workarea/admin/order\_view\_model.rb:
148
-
149
- ```
150
- module Workarea
151
- module Admin
152
- class OrderViewModel < ApplicationViewModel
153
- # ...
154
-
155
- def full_name
156
- if billing_address.present?
157
- "#{billing_address.first_name} #{billing_address.last_name}"
158
- elsif shipping_address.present?
159
- "#{shipping_address.first_name} #{shipping_address.last_name}"
160
- end
161
- end
162
-
163
- # ...
164
- end
165
- end
166
- end
167
- ```
168
-
169
- The store credit and full name examples demonstrate methods that are concerned with the _presentation_ of data. **View models keep presentation logic out of models** , which are concerned with business logic rather than presentation.
170
-
171
- ### Keep Controllers Lean
172
-
173
- As with presenting an order, presenting a product requires complex data reads across several contexts. Despite this, the Store Front's products controller is lean and easy to read:
174
-
175
- workarea-storefront/app/controllers/workarea/storefront/products\_controller.rb:
176
-
177
- ```
178
- module Workarea
179
- class Storefront::ProductsController < Storefront::ApplicationController
180
- before_filter :cache_page
181
-
182
- def show
183
- model = Catalog::Product.find_for_display!(params[:id])
184
-
185
- @product = Storefront::ProductViewModel.wrap(
186
- model,
187
- view_model_options
188
- )
189
-
190
- if request.xhr?
191
- render 'quickview'
192
- else
193
- render 'show'
194
- end
195
- end
196
- end
197
- end
198
- ```
199
-
200
- The read logic exists in the view model that wraps the model instance. **View models keep complicated read logic out of controllers**.
201
-
202
- ### Provide a Single Interface to the View
203
-
204
- The products controller above contains a familiar pattern: find the relevant model instance, wrap it in a view model, assign it to an instance variable, then render the view. The `@product` instance variable encapsulates all the data and logic needed to present the model, all wrapped up nicely for the view.
205
-
206
- By providing this single interface to the view, **view models reduce logic in views**. Keeping this logic out the view makes the logic easier to test and makes the view easier to read.
207
-
208
- Having explained the philosophy of view models, let's move on to the most important implementation details, starting with initialization.
209
-
210
- ## Initialization/Wrapping
211
-
212
- View model instances are initialized with a model instance and an optional hash of additional data. Each view model instance therefore "wraps" a model instance.
213
-
214
- The Store Front pages controller, for example, includes an instance of `PageViewModel` wrapping an instance of `Page` and an instance of `ContentViewModel` wrapping an instance of `Content`.
215
-
216
- workarea-storefront/app/controllers/workarea/storefront/pages\_controller.rb:
217
-
218
- ```
219
- module Workarea
220
- class Storefront::PagesController < Storefront::ApplicationController
221
- before_filter :cache_page
222
-
223
- def show
224
- model = Content::Page.find_by_slug(params[:id])
225
- @page = Storefront::PageViewModel.new(model, view_model_options)
226
- end
227
-
228
- def home_page
229
- @page = Storefront::ContentViewModel.new(
230
- Content.for('home_page'),
231
- view_model_options
232
- )
233
- end
234
-
235
- def robots; end
236
- def accessibility; end
237
- end
238
- end
239
- ```
240
-
241
- In both cases, `view_model_options` is passed as the additional data hash. This method is mixed into all Store Front controllers and returns the params from the controller with the current user merged in.
242
-
243
- ### Model Types
244
-
245
- The model being wrapped does not need to be a formal model (a Mongoid document), as demonstrated by the Admin searches controller:
246
-
247
- workarea-admin/app/controllers/workarea/admin/searches\_controller.rb:
248
-
249
- ```
250
- module Workarea
251
- module Admin
252
- class SearchesController < Admin::ApplicationController
253
- def show
254
- search = Search::Queries::AdminSearch.new(params)
255
- @search = SearchViewModel.new(search, params)
256
- end
257
- end
258
- end
259
- end
260
- ```
261
-
262
- In this example, the model is a search query object, and the params are passed as options.
263
-
264
- ### New vs Wrap
265
-
266
- You may have noticed that a few of the examples above create a view model instance using the `wrap` method rather than `new`. In fact, **`wrap` is the preferred API to create a view model and should be used when creating new view model instances**. The next major version of Workarea will use `wrap` exclusively. Beyond improved semantics, `wrap` differs technically from `new` in that (1) it can create an array of view models from an enumerable and (2) it may return a specialized view model type.
267
-
268
- ### Wrapping an Enumerable
269
-
270
- Passing an enumerable to `wrap` returns an array of view model instances. One such example is the `Storefront::DisplayContent` mixin:
271
-
272
- workarea-storefront/app/view\_models/workarea/storefront/display\_content.rb:
273
-
274
- ```
275
- module Workarea
276
- module Storefront
277
- module DisplayContent
278
- # ...
279
-
280
- def content_for(area)
281
- return [] unless content.present?
282
- blocks = content.blocks_for(area).select(&:active?)
283
- ContentBlockViewModel.wrap(blocks, options)
284
- end
285
-
286
- # ...
287
- end
288
- end
289
- end
290
- ```
291
-
292
- In this example, `blocks` is an array of `Content::Block` models. The `content_for` method returns an array of `ContentBlockViewModel` instances.
293
-
294
- ### Specialization
295
-
296
- Unlike `new`, `wrap` may return a view model instance of a different type. This occurs when `wrap` identifies a specialized view model type that is more appropriate. For example, `ContentBlockViewModel.wrap` will try to find a view model matching the specific block type, and `ProductViewModel.wrap` will try to find a view model matching the product's template type.
297
-
298
- While most view models inherit directly from `ApplicationViewModel`, "specialized" view models inherit from another view model that in turn inherits from `ApplicationViewModel`, giving them the properties of both view models.
299
-
300
- The excerpt below shows the Store Front's content block view model. Notice how the `locals` method returns a hash created from the model's data:
301
-
302
- workarea-storefront/app/view\_models/workarea/storefront/content\_block\_view\_model.rb:
303
-
304
- ```
305
- module Workarea
306
- module Storefront
307
- class ContentBlockViewModel < ApplicationViewModel
308
- def self.wrap(model, options = {})
309
- # ...
310
- end
311
-
312
- def partial
313
- # ...
314
- end
315
-
316
- def locals
317
- model.data.try(:symbolize_keys) || {}
318
- end
319
- end
320
- end
321
- end
322
- ```
323
-
324
- The category summary view model "specializes" the content block view model, overwriting the `locals` method and adding additional methods needed to present a category summary content block within the Store Front:
325
-
326
- workarea-storefront/app/view\_models/workarea/storefront/content\_blocks/category\_summary\_view\_model.rb:
327
-
328
- ```
329
- module Workarea
330
- module Storefront
331
- module ContentBlocks
332
- class CategorySummaryViewModel < ContentBlockViewModel
333
- include ProductBrowsing
334
-
335
- def locals
336
- { category: category, products: products }
337
- end
338
-
339
- def category
340
- # ...
341
- end
342
-
343
- def products
344
- # ...
345
- end
346
-
347
- # ...
348
- end
349
- end
350
- end
351
- end
352
- ```
353
-
354
- ### Wrap Example
355
-
356
- In a newly created Workarea application, the home page content is composed of a variety of content blocks. The following example console session uses those blocks to demonstrate (1) wrapping an enumerable and (2) specialized view model types:
357
-
358
- ```
359
- # Create an array of content block models
360
- irb(main):001:0> home_page_blocks = Workarea::Content.for('home_page').blocks
361
-
362
- # Wrap the array with ContentBlockViewModel
363
- irb(main):002:0> view_models = Workarea::Storefront::ContentBlockViewModel.wrap(home_page_blocks)
364
-
365
- # Confirm the return value is an array
366
- irb(main):003:0> view_models.class
367
- => Array
368
-
369
- # Print the type of each value in the array
370
- # Some are ContentBlockViewModel
371
- # Others are specialized types
372
- irb(main):004:0> puts view_models.map(&:class)
373
- Workarea::Storefront::ContentBlocks::HeroViewModel
374
- Workarea::Storefront::ContentBlocks::BannerViewModel
375
- Workarea::Storefront::ContentBlockViewModel
376
- Workarea::Storefront::ContentBlocks::VideoViewModel
377
- Workarea::Storefront::ContentBlocks::CategorySummaryViewModel
378
- Workarea::Storefront::ContentBlockViewModel
379
- Workarea::Storefront::ContentBlockViewModel
380
- ```
381
-
382
- ## Method Delegation
383
-
384
- It's important to understand the method delegation that occurs within view models. View models may replace existing methods on the models they wrap, as well as add additional methods to those models. **View model instances delegate to the model for all methods they have not replaced or added**.
385
-
386
- View models also provide a `model` method to access the wrapped model (and its methods) directly.
387
-
388
- The following example console session demonstrates these concepts:
389
-
390
- ```
391
- # Get a product model instance
392
- irb(main):027:0> product = Workarea::Catalog::Product.first
393
-
394
- # Create a view model instance from that model
395
- irb(main):028:0> product_view_model = Workarea::Storefront::ProductViewModel.wrap(product)
396
-
397
- # Access the original model's `images` method from the view model
398
- # It returns an array
399
- irb(main):031:0> product_view_model.model.images.class
400
- => Array
401
-
402
- # Now call the same method directly on the view model instance
403
- # The view model redefines that method, returning an `ImageCollection`
404
- irb(main):030:0> product_view_model.images.class
405
- => Workarea::Storefront::ProductViewModel::ImageCollection
406
-
407
- # Try to call `primary_image` on the original model
408
- # The method doesn't exist
409
- irb(main):034:0> product.primary_image
410
- => # NoMethodError: undefined method `primary_image' for #<Workarea::Catalog::Product:0x007f729c69a738>
411
-
412
- # However, it does exist on the view model
413
- # The view model has augmented the original model
414
- irb(main):035:0> product_view_model.primary_image
415
- => #<Workarea::Catalog::ProductPlaceholderImage _id: 575b276d7765623aca000091, created_at: 2016-06-10 20:47:41 UTC, updated_at: 2016-06-10 20:47:41 UTC, image_uid: "2016/06/10/5eggsd9wcc_product_placeholder.jpg">
416
-
417
- # The view model does not define a `categories` method
418
- irb(main):037:0> product_view_model.methods.include?(:categories)
419
- => false
420
-
421
- # However, calling the method on the view model returns a `Mongoid::Criteria`
422
- # The view model delegates to the model, which defines this method
423
- irb(main):038:0> product_view_model.categories
424
- => #<Mongoid::Criteria
425
- selector: {"deleted_at"=>nil, "product_ids"=>{"$in"=>["2F2DA168D8"]}}
426
- options: {}
427
- class: Workarea::Catalog::Category
428
- embedded: false>
429
- ```
430
-
431
- ## View Model Interface Diagram
432
-
433
- The diagram that follows brings together many of the ideas from above:
434
-
435
- * As needed, the view model initializes and queries a variety of objects to extend the interface of the original "wrapped" model
436
- * The view model instance, which provides this extended interface, is bound to an instance variable
437
- * The view "receives" this instance variable, from which it can query all data necessary to render the page or fragment
438
-
439
- ![View Model Interface](../images/view-model-interface.png)
440
-
441
-
442
- ## View Models vs Helpers
443
-
444
- Rails includes the concept of <dfn>helpers</dfn>—classes whose methods are accessible in views—for the purpose of extracting view logic into testable classes. Helpers overlap conceptually with view models, and Workarea makes use of both object types. In general, Workarea applications prefer view models over helpers, largely because view models are easier to decorate and test. However, Workarea does make use of helper methods, primarily for the following use cases:
445
-
446
- - Methods concerned with constructing HTML strings, such as a list of class values for an HTML element.
447
- - Methods that return re-usable snippets of HTML, such as `datetime_picker_tag`.
448
- - Methods that depend on or compose Rails' own view helpers, such as `render_content_block`, shown below.
449
- - Methods that depend on arguments received from the view.
450
-
451
- The following examples demonstrate the typical usage of helper methods within a Workarea application. Notice that each method is concerned with constructing an HTML string, and some methods depend on helpers provided by Rails.
452
-
453
- workarea-storefront/app/helpers/workarea/storefront/content\_helper.rb:
454
-
455
- ```
456
- module Workarea
457
- module Storefront
458
- module ContentHelper
459
- def render_content_block(block)
460
- render(partial: block.partial, locals: block.locals)
461
- end
462
-
463
- def render_content_blocks(blocks)
464
- blocks.inject('') do |result, block|
465
- result << render_content_block(block)
466
- result
467
- end.html_safe
468
- end
469
-
470
- def hero_link_class(hero_link_style)
471
- style = hero_link_style.parameterize
472
-
473
- if style == 'button'
474
- 'button'
475
- else
476
- "hero-content-block __action-text hero-content-block__ action-text--#{style}"
477
- end
478
- end
479
- end
480
- end
481
- end
482
- ```
483
-
484
- workarea-storefront/app/helpers/workarea/storefront/credit\_cards\_helper.rb:
485
-
486
- ```
487
- module Workarea
488
- module Storefront
489
- module CreditCardsHelper
490
- def credit_card_issuer_icon(issuer)
491
- content_tag(
492
- :span,
493
- issuer,
494
- class: credit_card_issuer_icon_class(issuer),
495
- title: issuer
496
- )
497
- end
498
-
499
- def credit_card_issuer_icon_class(issuer)
500
- if Workarea.config.credit_card_issuers.values.include?(issuer)
501
- "payment-icon payment-icon--#{issuer.parameterize}"
502
- else
503
- 'payment-icon'
504
- end
505
- end
506
- end
507
- end
508
- end
509
- ```
@@ -1,14 +0,0 @@
1
- ---
2
- title: Views
3
- excerpt: Workarea views are written in Haml, but are otherwise no different from vanilla Rails views.
4
- ---
5
-
6
- # Views
7
-
8
- Workarea views are written in [Haml](http://haml.info/), but are otherwise no different from vanilla Rails views.
9
-
10
- You do not need to stick with Haml when [overriding views](overriding.html). You may change the file extension and use whichever templating language you prefer and Rails will prefer your view over the same view from Workarea.
11
-
12
- For HTML naming conventions and idioms used in Workarea, review the [stylesheet coding standards](stylesheet-coding-standards.html).
13
-
14
-