gitlab-org--gitlab-foss/app/presenters
Shinya Maeda 7ba89e4ac4 Expose refspec and depth to runner
fix

fix and fix

Allow full ref specification for pipeline creation

Add spec

Support backward compatibility

Use ref path

Runner feature flag

Simplify the things

Support fork workflow (Public only)

Expose ref spec

Use refspec

Glooming

Decouple unrelated changes

Add changelog

Revert unrelated file

Decouple unnecessary

Add spec

Use refspecs

Fix changelog

Simplify

Fix coding offence

Fix

a

ok

ok

ok

ok

ok

a

a

Fix

Add workaround for ignore_column

Fix git depth

Fix coding offence

Fix spec

Simplify more

Do not set ignored column

Fix tests

Fix pipeline

Fix spec

fix fixture yes

Revert nonsense

fix

Revert more

ok

Decouple mr pipelines

fix spev

Remove unrelated changes
2019-02-25 13:40:15 +09:00
..
ci Expose refspec and depth to runner 2019-02-25 13:40:15 +09:00
clusters Move code to presenter 2018-12-17 09:51:53 +13:00
conversational_development_index Disable existing offenses for the CodeReuse cops 2018-09-11 17:32:00 +02:00
projects/settings Disable existing offenses for the CodeReuse cops 2018-09-11 17:32:00 +02:00
blob_presenter.rb Centralize loading blob data before highlighting 2018-10-30 15:44:55 +08:00
clusterable_presenter.rb Allow users to add cluster with ancestors 2018-12-24 10:28:40 -06:00
commit_presenter.rb [master] Pipelines section is available to unauthorized users 2019-01-31 16:52:50 +01:00
commit_status_presenter.rb Allow to make builds soft-archived. 2018-11-05 15:51:57 +01:00
generic_commit_status_presenter.rb Enable frozen string in presenters and policies 2018-07-24 13:18:25 -07:00
group_clusterable_presenter.rb Correct link to group clusters docs 2018-12-06 16:25:18 +13:00
group_member_presenter.rb Enable frozen string in presenters and policies 2018-07-24 13:18:25 -07:00
issue_presenter.rb Suggests issues when typing title 2018-11-27 15:10:40 +00:00
member_presenter.rb Resolve "Can add an existing group member into a group project with new permissions but permissions are not overridden" 2018-12-06 13:15:29 +00:00
members_presenter.rb Enable frozen string in presenters and policies 2018-07-24 13:18:25 -07:00
merge_request_presenter.rb [master] Pipelines section is available to unauthorized users 2019-01-31 16:52:50 +01:00
project_clusterable_presenter.rb Reverse view override as EE has an override too 2018-11-08 23:28:30 +13:00
project_member_presenter.rb Enable frozen string in presenters and policies 2018-07-24 13:18:25 -07:00
project_presenter.rb Fix the border style of CONTRIBUTING button when it exists 2019-02-12 10:11:19 +09:00
README.md
user_presenter.rb Suggests issues when typing title 2018-11-27 15:10:40 +00:00

Presenters

This type of class is responsible for giving the view an object which defines view-related logic/data methods. It is usually useful to extract such methods from models to presenters.

When to use a presenter?

When your view is full of logic

When your view is full of logic (if, else, select on arrays etc.), it's time to create a presenter!

When your model has a lot of view-related logic/data methods, you can easily move them to a presenter.

Why are we using presenters instead of helpers?

We don't use presenters to generate complex view output that would rely on helpers.

Presenters should be used for:

  • Data and logic methods that can be pulled & combined into single methods from view. This can include loops extracted from views too. A good example is https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7073/diffs.
  • Data and logic methods that can be pulled from models.
  • Simple text output methods: it's ok if the method returns a string, but not a whole DOM element for which we'd need HAML, a view context, helpers etc.

Why use presenters instead of model concerns?

We should strive to follow the single-responsibility principle, and view-related logic/data methods are definitely not the responsibility of models!

Another reason is as follows:

Avoid using concerns and use presenters instead. Why? After all, concerns seem to be a core part of Rails and can DRY up code when shared among multiple models. Nonetheless, the main issue is that concerns dont make the model object more cohesive. The code is just better organized. In other words, theres no real change to the API of the model.

https://www.toptal.com/ruby-on-rails/decoupling-rails-components

Benefits

By moving pure view-related logic/data methods from models & views to presenters, we gain the following benefits:

  • rules are more explicit and centralized in the presenter => improves security
  • testing is easier and faster as presenters are Plain Old Ruby Object (PORO)
  • views are more readable and maintainable
  • decreases number of CE -> EE merge conflicts since code is in separate files
  • moves the conflicts from views (not always obvious) to presenters (a lot easier to resolve)

What not to do with presenters?

  • Don't use helpers in presenters. Presenters are not aware of the view context.
  • Don't generate complex DOM elements, forms etc. with presenters. Presenters can return simple data as texts, and URLs using URL helpers from Gitlab::Routing but nothing much more fancy.

Implementation

Presenter definition

Every presenter should inherit from Gitlab::View::Presenter::Simple, which provides a .presents method which allows you to define an accessor for the presented object. It also includes common helpers like Gitlab::Routing and Gitlab::Allowable.

class LabelPresenter < Gitlab::View::Presenter::Simple
  presents :label

  def text_color
    label.color.to_s
  end

  def to_partial_path
    'projects/labels/show'
  end
end

In some cases, it can be more practical to transparently delegate all missing method calls to the presented object, in these cases, you can make your presenter inherit from Gitlab::View::Presenter::Delegated:

class LabelPresenter < Gitlab::View::Presenter::Delegated
  presents :label

  def text_color
    # color is delegated to label
    color.to_s
  end

  def to_partial_path
    'projects/labels/show'
  end
end

Presenter instantiation

Instantiation must be done via the Gitlab::View::Presenter::Factory class which detects the presenter based on the presented subject's class.

class Projects::LabelsController < Projects::ApplicationController
  def edit
    @label = Gitlab::View::Presenter::Factory
      .new(@label, current_user: current_user)
      .fabricate!
  end
end

You can also include the Presentable concern in the model:

class Label
  include Presentable
end

and then in the controller:

class Projects::LabelsController < Projects::ApplicationController
  def edit
    @label = @label.present(current_user: current_user)
  end
end

Presenter usage

%div{ class: @label.text_color }
  = render partial: @label, label: @label

You can also present the model in the view:

- label = @label.present(current_user: current_user)

%div{ class: label.text_color }
  = render partial: label, label: label