Skip to content

Rails views

Teddy Wing edited this page Apr 3, 2018 · 2 revisions

Decorators

Usage

We define only a single decorator per model that must inherit from AF83::Decorator. This model decorator handles both collections and instances. To decorate an Item object:

# app/controllers/items_controller.rb
def index
  # ...
  @items = ItemDecorator.decorate(@items)
  # ...
end

def show
  # ...
  @item = @item.decorate
  # ...
end

The actions on the collection are defined at the root of the decorator, while those for instances are defined with the help of a with_instance_decorator block.

To define an action, we use the action_link method. The method accepts these options:

  • on: only shows the link on the pages for the listed actions (e.g. on: %i(show index))
  • if: takes a Proc and only displays the link if the proc result is truthy
  • policy: only shows the link if the current user has the permission for the decorated object and action link (takes an action argument, for example :edit, or :create)
  • feature: like policy, but for a feature
  • weight: allow the links' display order to be changed, with weight: 1 shown first (by default, the declaration order is used)

Actions are also split into groups. These can be customised in several ways:

groups: {
  primary: true,
  secondary: %i(index show),
  any_other_group: :index
}

Shortcuts are available for the primary, secondary, and footer groups. These enable us to write action_link primary: :index instead of action_link groups: { primary: :index }.

Link content is defined in a block. Each method called on the object passed into the block is converted into an attribute on the resulting HTML tag, except for these:

  • extra_class: Adds one or more classes to the link. Takes either an Array or a String.
  • class: Replaces the link's classes. Takes either an Array or a String.
  • type: Allows the HTML tag to be changed. The only value currently implemented is :button. All others fall back on <a>.

Shortcuts

Four methods are available to define common actions:

  • create_action_link: adds a create link for a collection
  • show_action_link: adds a show link on an instance
  • edit_action_link: adds an edit link on an instance
  • destroy_action_link: adds a destroy link on an instance

These are defined in the AF83::Decorator::EnhancedDecorator module.

Behavior

The default behavior is as follows:

On the index page

Actions from the collection's primary group are rendered in the main section of the header (and retained in the "sticky" header). Below the main header, actions for the collection's secondary group are rendered.

In the TableBuilderHelper, all actions in the primary, secondary, and footer groups are rendered in a menu next to each instance, separated by group. The footer group always comes last.

On the show page

Actions from the object's primary group are rendered in the main section of the header (and retained in the "sticky" header). Below the main header, actions for the object's secondary group are rendered.

Examples

Simple decorator

class CalendarDecorator < AF83::Decorator
  decorates Calendar

  create_action_link

  with_instance_decorator do |instance_decorator|
    instance_decorator.show_action_link
    instance_decorator.edit_action_link
    instance_decorator.destroy_action_link do |l|
      l.data {{ confirm: h.t('calendars.actions.destroy_confirm') }}
    end
  end
end

More complex decorator

class LineDecorator < AF83::Decorator
  decorates Chouette::Line

  create_action_link do |l|
    l.content t('lines.actions.new')
    l.href    { h.new_line_referential_line_path(context[:line_referential]) }
  end

  with_instance_decorator do |instance_decorator|
    instance_decorator.show_action_link do |l|
      l.content t('lines.actions.show')
      l.href   { [context[:line_referential], object] }
    end

    instance_decorator.action_link do |l|
      l.content t('lines.actions.show_network')
      l.href   { [context[:line_referential], object.network] }
    end

    instance_decorator.action_link do |l|
      l.content  t('lines.actions.show_company')
      l.href     { [context[:line_referential], object.company] }
      l.disabled { object.company.nil? }
    end

    can_edit_line = ->(){ h.policy(Chouette::Line).create? && context[:line_referential].organisations.include?(context[:current_organisation]) }

    instance_decorator.with_condition can_edit_line do
      edit_action_link do |l|
        l.content {|l| l.primary? ? h.t('actions.edit') : h.t('lines.actions.edit') }
        l.href    { h.edit_line_referential_line_path(context[:line_referential], object.id) }
      end

      action_link on: :index, secondary: :index do |l|
        l.content t('lines.actions.new')
        l.href    { h.new_line_referential_line_path(context[:line_referential]) }
      end
    end

    instance_decorator.action_link policy: :deactivate, secondary: :show, footer: :index do |l|
      l.content  { h.deactivate_link_content('lines.actions.deactivate') }
      l.href     { h.deactivate_line_referential_line_path(context[:line_referential], object) }
      l.method   :put
      l.data     confirm: h.t('lines.actions.deactivate_confirm')
      l.extra_class "delete-action"
    end

    instance_decorator.action_link policy: :activate, secondary: :show, footer: :index do |l|
      l.content  { h.activate_link_content('lines.actions.activate') }
      l.href     { h.activate_line_referential_line_path(context[:line_referential], object) }
      l.method   :put
      l.data     confirm: h.t('lines.actions.activate_confirm')
      l.extra_class "delete-action"
    end

    instance_decorator.destroy_action_link do |l|
      l.content  { h.destroy_link_content('lines.actions.destroy') }
      l.href     { h.line_referential_line_path(context[:line_referential], object) }
      l.data     confirm: h.t('lines.actions.destroy_confirm')
      l.extra_class "delete-action"
    end
  end
end

Breadcrumb

The breadcrumb is built with the Gretel gem. Its configuration is stored in the config/breadcrumbs.rb file.