Skip to content

Instantly share code, notes, and snippets.

@elskwid
Last active January 12, 2018 05:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elskwid/fcb7a1cec5e26eb7e697d43fe0182899 to your computer and use it in GitHub Desktop.
Save elskwid/fcb7a1cec5e26eb7e697d43fe0182899 to your computer and use it in GitHub Desktop.
Simple Rails Presenter and View Presenter (so I don't forget)
# frozen_string_literal: true
module Foo
# Simple presenter module
#
# Uses Charlatan to create an `Foo::Presenter` module for use in the app.
# This isn't *strictly* a presenter - it's somewhere between a presenter,
# proxy, and/or decorator.
#
# Including `Foo::Presenter.new(:presented_thing)` in a class will
# create a module (Charlatan inherits from Module) that, in turn, creates
# an initializer so the proxied object is stored in the instance and
# available through an instance method.
#
# Example:
# class MyPresenter
# include Foo::Presenter.new(:array)
#
# def second_item
# array.second
# end
# end
#
# array = [1, 2, 3]
# my_presenter = MyPresenter.new(array)
#
# # available at the instance method
# my_presenter.array
# #=> [1, 2, 3]
#
# # presenter appears *to be* the array
# my_presenter.length
# #=> 3
#
# # can decorate with new methods
# my_presenter.second_item
# #=> 2
class Presenter < Charlatan
end
end
# frozen_string_literal: true
module Foo
# Simple presenter for view-related uses that mixes in some useful Rails
# view helpers.
#
# Of note, the view presenter includes the Rails URL helpers so things like
# `link_to` and `url_for` work. These are tricky helpers that require a few
# dependencies and they have a very specific load order.
#
# See example in Foo::Presenter
class ViewPresenter < Presenter
def initialize(*args)
super # let Charlatan do its thing
include ActionView::Helpers::DateHelper
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::SanitizeHelper
include ActionView::Helpers::TextHelper
include ActionView::Helpers::TranslationHelper
include ActionView::Helpers::UrlHelper
include InlineSvg::ActionView::Helpers
include ApplicationHelper # bring in our global helpers
end
def included(mod)
mod.extend ClassMethods
mod.extend Sanitizers
mod.include InstanceMethods
mod.include Rails.application.routes.url_helpers
end
# Class methods(s) needed by various helpers
module ClassMethods
# Delegate the default urls options to ActionMailer
def default_url_options
ActionMailer::Base.default_url_options.merge(
protocol: Rails.env.in?(%w[test development]) ? "http" : "https"
)
end
def present_each(collection, *args, **kwargs)
return unless collection.respond_to?(:map)
collection.map { |item| new(item, *args, **kwargs) }
end
end
# Instance method(s) needed by various helpers
module InstanceMethods
def present_collection(collection:, presenter:)
collection.map { |item| presenter.new(item) }
end
# url helpers require options and default options or they override
def url_options
self.class.default_url_options
end
alias default_url_options url_options
# return the value or a default
def value_or_default(value, default = nil)
value.present? ? value : default
end
end
end
# Sanitizer methods required by `SanitizeHelper`
module Sanitizers
def full_sanitizer
@full_sanitizer ||= Rails::Html::FullSanitizer.new
end
def link_sanitizer
@link_sanitizer ||= Rails::Html::LinkSanitizer.new
end
def white_list_sanitizer
@white_list_sanitizer ||= Rails::Html::WhiteListSanitizer.new
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment