From 6e1703e1c8f79f99028c8b7a968b01c4981563f4 Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Wed, 23 May 2018 14:03:37 -0400 Subject: [PATCH] Begin patterns documentation including overview and presenter pattern --- _data/sidebars/home_sidebar.yml | 14 ++ pages/a-z.md | 8 + .../developer_resources/patterns/overview.md | 26 ++ .../patterns/presenters.md | 223 ++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 pages/samvera/developer_resources/patterns/overview.md create mode 100644 pages/samvera/developer_resources/patterns/presenters.md diff --git a/_data/sidebars/home_sidebar.yml b/_data/sidebars/home_sidebar.yml index 84cf656b..86992767 100644 --- a/_data/sidebars/home_sidebar.yml +++ b/_data/sidebars/home_sidebar.yml @@ -136,6 +136,20 @@ entries: url: /toggle-features.html output: web + subfolders: + + - title: 'Design Patterns' + output: web + subfolderitems: + + - title: Overview + url: /patterns-overview.html + output: web + + - title: Presenters + url: /patterns-presenters.html + output: web + - title: Coding Style with RuboCop url: /best-practices-coding-styles.html output: web diff --git a/pages/a-z.md b/pages/a-z.md index dc71831a..757671db 100644 --- a/pages/a-z.md +++ b/pages/a-z.md @@ -165,6 +165,10 @@ sidebar: home_sidebar
Deprecation
+ Design Pattern - Overview +
+ Design Pattern - Presenters +
Development Community
Development Resources @@ -353,6 +357,8 @@ sidebar: home_sidebar
Overview of Collections
+ Overview of Design Pattern +
@@ -375,6 +381,8 @@ sidebar: home_sidebar
Prereq: Generating a Work Type
+ Presenters Design Pattern +
Product Owners
Pull Request diff --git a/pages/samvera/developer_resources/patterns/overview.md b/pages/samvera/developer_resources/patterns/overview.md new file mode 100644 index 00000000..59f0e29b --- /dev/null +++ b/pages/samvera/developer_resources/patterns/overview.md @@ -0,0 +1,26 @@ +--- +title: "Overview of Design Pattern" +permalink: patterns-overview.html +folder: samvera/developer_resources/patterns/overview.md +sidebar: home_sidebar +a-z: ['Design Pattern - Overview', 'Overview of Design Pattern'] +keywords: Design Patterns +tags: [development_resources] +categories: Design Patterns +--- + + + +Models, Views, and Controllers (MVC) are the basic patterns provided by Rails. To adhere to the goal of single responsibility, we do not want to include code beyond the minimum required for these classes. Additional processing and business logic are addressed in classes outside the MVC classes. Design patterns are used to organize business logic that falls beyond the basic MVC pattern. + +| Pattern | Primary Goal | +| ------- | ------------ | +| Actors | Single responsibility classes that each address one action that is part of the create/update process for objects. | +| Forms | Isolate new/edit form views from business logic code. Primarily used to control which and how data fields are displayed in the forms. | +| Indexers | Creates solr documents for objects. | +| Inputs | Custom processing of input fields in forms. Used to with controlled vocabularies and when the input of one field effects options for another field. | +| Jobs | Background jobs. | +| Presenters | Isolate views from business logic code related to showing information. Primarily used for constructing object show pages. | +| Search Builders | Used to construct solr queries. | +| Services | Handle processing that falls outside of other patterns. Characterized by each service having a single responsibility. | + diff --git a/pages/samvera/developer_resources/patterns/presenters.md b/pages/samvera/developer_resources/patterns/presenters.md new file mode 100644 index 00000000..ae872e74 --- /dev/null +++ b/pages/samvera/developer_resources/patterns/presenters.md @@ -0,0 +1,223 @@ +--- +title: "Presenters Design Pattern" +permalink: patterns-presenters.html +folder: samvera/developer_resources/patterns/presenters.md +sidebar: home_sidebar +a-z: ['Design Pattern - Presenters', 'Presenters Design Pattern'] +keywords: Design Patterns +tags: [development_resources] +categories: Design Patterns +--- + +# Understanding the Presenters Design Pattern + + + +## Characteristics: +* Presenters are used to hide implementation details from views. They serve as a go-between for controllers and views. +* Presenters provide access to controller instance variables. +* `@presenter` should be the only instance variable accessed in the view. +* `@presenter` can be passed as `presenter` to partials rendered from the primary view. +* The same presenter can be shared by multiple views and partials. +* Presenters can be used with any kind of view. Although, they are not used with new/edit forms. The Forms pattern performs a similar role for the forms. + +This documentation uses object show page presenters to highlight some characteristics of presenters. Show page presenters are the most common to customize with overrides ond extensions. + +## A deeper dive into some of the show page presenters methods + +Show pages are views that display information for a single object in the repository. Show page presenters you may want to explore are... + +* [app/presenters/hyrax/admin_set_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/admin_set_presenter.rb) +* [app/presenters/hyrax/collection_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_presenter.rb) +* [app/presenters/hyrax/work_show_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/work_show_presenter.rb) +* [app/presenters/hyrax/file_set_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/file_set_presenter.rb) +* [app/presenters/hyrax/presents_attributes.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/presents_attributes.rb) + +### Delegate retrieval to solr_document + +Access to property values is provided by the solr document. To allow presenters to surface these values, the metadata access methods are delegated to `solr_document`. All the show page presenters use delegation in this way. + +*Example Default* + +[actual default for works](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/work_show_presenter.rb#L38-L42) + +```ruby + # Metadata Methods + delegate :title, :date_created, :description, + :creator, :contributor, :subject, :publisher, :language, :embargo_release_date, + :lease_expiration_date, :license, :source, :rights_statement, :thumbnail_id, :representative_id, + :rendering_ids, :member_of_collection_ids, to: :solr_document +``` + +*Example Extension* + +The original delegations still exist. The following is an example of adding more delegations for custom metadata fields. + +```ruby + # Custom Metadata Methods + delegate :contact_email, :contact_phone, :department, to: :solr_document +``` + +### Specify which properties to show + +For works, this is not determined by the presenter. It is determined by [app/views/curation_concerns/base/_attribute_rows.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/curation_concerns/base/_attribute_rows.html.erb). For more information on updating `_attribute_rows.html.erb`, see the Customizing Metadata tutorial's lesson on Modifying the Show Page. + +For collections, this is determined by the `terms` method in the presenter. + +*Example Default* + +[actual default for collections](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_show_presenter.rb#L41-L46) + +```ruby + # Terms is the list of fields displayed by + # app/views/collections/_show_descriptions.html.erb + def self.terms + [:total_items, :size, :resource_type, :creator, :contributor, :keyword, :license, :publisher, :date_created, :subject, + :language, :identifier, :based_near, :related_url] + end +``` + +*Example Override* + +In this case, the `terms` method is completely overridden and only the terms defined in this `self.terms` will be displayed. In this example, a few of the default properties are included and custom properties are added. Any default property not included in this list will not be shown on the collection show page. + +```ruby + # Terms is the list of fields displayed by + # app/views/collections/_show_descriptions.html.erb + def self.terms + [:total_items, :size, :contact_email, :contact_phone, :department, :keyword] + end +``` + +### Hiding terms with blank values + +By default, terms with blank values are hidden. + +* For works, I do not know if you can change this. +* For collections, the hiding of terms with blank values is controlled by the `terms_with_values` method. + +*Example Default* + +The default code for object presenters excludes display of terms with `nil` values in method... + +[actual default for collections](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_show_presenter.rb#L48-L50) + +``` + def terms_with_values + self.class.terms.select { |t| self[t].present? } + end +``` + +*Example Override* + +If you want terms without values to be displayed, override this method with... + +``` + def terms_with_values + # Return all terms even if they don't have values + self.class.terms + end +``` + +If your data has blank strings, you can ignore the blank string values too by overriding this method with... + +``` + def terms_with_values + # Ignore missing and blank values + self.class.terms.select { |t| self[t].present? && self[t] != [""] } + end +``` + +## Example methods designed to isolate view from business logic code + +### Example work presenter method + +*Method in work presenter* + +[app/presenters/hyrax/work_show_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/work_show_presenter.rb#L136-L138) + +``` + def work_featurable? + user_can_feature_works? && solr_document.public? + end +``` + +*Used in view* + +[app/views/hyrax/base/_show_actions.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/hyrax/base/_show_actions.html.erb#L32-L40) + +``` + <% if presenter.work_featurable? %> + <%= link_to "Feature", hyrax.featured_work_path(presenter, format: :json), + data: { behavior: 'feature' }, + class: presenter.display_unfeature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + + <%= link_to "Unfeature", hyrax.featured_work_path(presenter, format: :json), + data: { behavior: 'unfeature' }, + class: presenter.display_feature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + <% end %> +``` + +[Additional work presenter methods used to isolate business logic](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_presenter.rb#L63-L85) + + +### Example collection presenter method + +*Method in collection presenter* + +[app/presenters/hyrax/collection_presenter.rb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_presenter.rb#L83-L85) + +``` + def collection_type_badge + content_tag(:span, collection_type.title, class: "label", style: "background-color: " + collection_type.badge_color + ";") + end +``` + +*Used in view* + +* [app/views/hyrax/dashboard/collections/_collection_title.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/hyrax/dashboard/collections/_collection_title.html.erb#L18) + +``` +
+

+ <% # List multiple titles %> + <% presenter.title.each_with_index do |title, index| %> + <%= title %> + <% end %> +

+ <%= presenter.permission_badge %> + <%= presenter.collection_type_badge %> +
+``` + +*Also used in views...* + +* [app/views/catalog/_index_header_list_collection.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/catalog/_index_header_list_collection.html.erb#L3) +* [app/views/hyrax/my/collections/_list_collections.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/hyrax/my/collections/_list_collections.html.erb#L60) +* [app/views/hyrax/collections/show.html.erb](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/views/hyrax/collections/show.html.erb#L14) + +[Additional collection presenter methods used to isolate business logic](https://github.com/samvera/hyrax/blob/v2.1.0.rc3/app/presenters/hyrax/collection_presenter.rb#L63-L85) + +## Overriding and Custom Presenter Methods + + + +On occasion you may want to change the behavior of an existing presenter method. For example, in a local app, we wanted to limit the `total_items` method to return a count of a specific type of work only. We used class prepending to make the override, so our changed looks like... + +``` +# Based on the Module#prepend pattern in ruby which is used in some Hyrax. +# Uses the to_prepare Rails hook in application.rb to inject this module to override Hyrax::AdminSetPresenter module +module PrependedPresenters::AdminSetPresenter + # Override Hyrax::AdminSetPresenter#total_items method + # and filter query to only include publications in count + def total_items + ActiveFedora::SolrService.count("{!field f=isPartOf_ssim}#{id}", fq: "has_model_ssim:Publication") + end +end +``` + +You may also want to add custom methods to presenters. This is also done by adding the new method to the presenter prepend class and then adjusting the view to use the new presenter method. + +## Presenters used in context + +See Customizing Metadata tutorial's lesson on Modifying the Show Page which covers changes required beyond modifying presenters to customize how data is shown on an object's show page.