Decorators
A Decorator is linked to a Model. The goal is to extend the behaviors of a model without touching it directly. A decorator is used for specific use cases in the application. Mostly for Presenters or Views.
Role of a Decorator
The goal is to keep models as light as possible and extend them with reusable Decorators.
Location
app/decorators/
- Should be suffix with
_decorator.rb
Structure of a Decorator
Dos
- Wrap a model instance with view-related logic
- Formating
- Extend a Model to add business logic
- Use decorators in Presenters. Then a Presenter should only be used in Views.
- You can create multiple decorators per model because you might have different use cases for a particular model.
- May call view helpers (include them).
Don'ts
- Work on different models at the same time, in this case, you might need a Presenters or a Query Object.
- Make it too big: create different decorators is needed.
Code
module Handbook
# Responsible for theme presentation in school admin's back office
class ThemeDecorator < Draper::Decorator
include ActionView::Helpers
include Backend::Handbook::CollapseHelpers
delegate_all
# Decorated articles associated to the Handbook::Theme
# See Handbook::ArticleDecorator
def children
articles.includes(:translations, :curriculums).map(&:decorate)
end
# The Handbook::Theme does not have it's own activation status
# Its activation status therefore depends on the activation status of its articles
def activation_status
content_tag(:span, activation_status_text, class: activation_status_class)
end
# Active articles associated to the Handbook::Theme in the current locale
def active_children_count
children.count(&:active?)
end
# Are there any active in the current locale articles with curriculums
# in the Handbook::Theme associated articles?
def any_active_children_targeted?
return false unless active_children_count > 0
children.select(&:active?).any?(&:targeted?)
end
# Returns a no description message of the Handbook::Theme description is missing
# Returns a formatted description of the Handbook::Theme otherwise
def formatted_description
if description.empty?
I18n.t('decorators.handbook_theme.no_description')
else
simple_format(description)
end
end
private
# Depends of the number of active in the current locale articles associated to the theme
def activation_status_text
I18n.t(
'decorators.handbook_menu_items.activation_status',
count: active_children_count
)
end
def activation_status_class
any_active_children? ? 'label label-success' : 'label label-default'
end
def any_active_children?
active_children_count > 0
end
end
end