Skip to content

niko/representer

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

# (Re)Presenters for Rails
# A possible presenter solution.
# Ask/Write florian.hanke@gmail.com if you have questions/feedback, thanks! :)
# Fork if you have improvements. Tell me where to merge them from, thanks!
#
# Problem: Display Methods are not well placed either in
# * models: Violation of the MVC principle.
# * helpers: No Polymorphism.
# Solution:
# A thin proxy layer over a model, with access to the controller, used by the view or controller.
# 
# IMPORTANT NOTE:
# As of yet it is needed to copy the representer/views/presenters/collection
# directory to the corresponding location in app/views/presenters/collection.
# This is only needed if you wish to use the collection presenter.
# Note: Rewrite the collection templates as needed, they are rather basic.
#
# * Getting a presenter in a view or a controller.
#
# Call presenter_for:
# Note: By convention, uses Presenters::Model::Class::Name, thus prefixing Presenters:: to
#       the model class name.
presenter_instance = presenter_for model_instance

# * Getting a collection presenter in a view.
#
# The collection presenter renders each of the given items with its presenter.
#
# Call collection_presenter_for:
collection_presenter_instance = collection_presenter_for enumerable_containing_model_instances
# Rendering a list.
collection_presenter_instance.list
# Rendering a collection.
collection_presenter_instance.collection
# Rendering a table.
collection_presenter_instance.table
# Rendering a pagination.
# Note: Only works if the passed parameter for collection_presenter_for is a PaginationEnumeration.
collection_presenter_instance.pagination

# * Writing filtered delegate methods on the presenter.
#
# Will create two delegate methods first_name and last_name that delegate to the model.
model_reader :first_name, :last_name
# Will create a description delegate method that filters the model value through h.
model_reader :description, :filter_through => :h
# Will create a description delegate method that filters the model value through first textilize, then h.
model_reader :description, :filter_through => [:textilize, :h]
# Will create both a first_name and last_name delegate method
# that filters the model value through first textilize, then h.
model_reader :first_name, :last_name, :filter_through => [:textilize, :h]
# Note: Filter methods can be any method on the presenter with arity 1.

# * Rendering presenter templates
#
# Use render_as(template_name, format = nil).
#
# Gets a Presenters::Model::Class instance
presenter = presenter_for Model::Class.new
# Gets a Presenters::<model_instance.class.name> instance
presenter = presenter_for model_instance
# Renders the 'example' partial in presenters/model/class.
# Note: Renders a format depending on the request. ../index.text will render example.text.erb.
presenter.render_as :example
# Renders the 'example.text.erb' partial in presenters/model/class.
presenter.render_as :example, :text

# * Rails Helpers in Presenters
#
# Use helper as in the controller.
helper ActionView::Helpers::UrlHelper
helper ApplicationHelper
# Note: It is helpful to create a superclass to all presenters in the project
#       with generally used helpers.
# We use Presenters::Project a lot, for example. See example below.

# * Controller Delegate Methods
#
# Use controller_method(*args).
#
# Delegates current_user and logger on the presenter to the controller.
controller_method :current_user, :logger

# * Big Example
#
# The following classes all have specs of course ;) But are not shown since they don't help the example.

# Presenters superclass for this project.
#
# We include all of Rails' helpers for the presenters in this project.
# Also, we include the ApplicationHelper.
#
# We delegate logger and current_user calls in the presenters to
# the active controller.
#
class Presenters::Project < Presenters::Base
  
  # All of Rails' standard helpers.
  helper ActionView::Helpers::ActiveRecordHelper
  helper ActionView::Helpers::TagHelper
  helper ActionView::Helpers::FormTagHelper
  helper ActionView::Helpers::FormOptionsHelper
  helper ActionView::Helpers::FormHelper
  helper ActionView::Helpers::UrlHelper
  helper ActionView::Helpers::AssetTagHelper
  helper ActionView::Helpers::PrototypeHelper
  helper ActionView::Helpers::TextHelper
  
  helper ApplicationHelper
  
  controller_method :logger, :current_user
  
end

# All items have a description that needs to be filtered by textilize.
#
class Presenters::Item < Presenters::Project
  model_reader :description, :filter_through => :textilize
  # Use price in the view as follows:
  # = presenter.price - will display e.g. 16.57 CHF, since it is filtered first through localize_currency
  model_reader :price, :filter_through => :localize_currency
  
  # Converts a database price tag to the users chosen value, with the users preferred currency appended.
  # If the user is Swiss, localize_currency will convert 10 Euros to "16.57 CHF" 
  #
  def localize_currency(price_in_euros)
    converted_price = current_user.convert_price(price_in_euros)
    "#{converted_price} #{current_user.currency.to_s}"
  end
end

# This class also has partial templates in the directory
#   app/views/presenters/book
# that are called
#   _cart_item.html.haml
#   _cart_item.text.erb
#
# Call presenter_for on a book in the view or controller to get this presenter.
#
class Presenters::Book < Presenters::Item
  model_reader :author, :title, :pages
  model_reader :excerpt, :filter_through => :textilize
  
  def header
    content_tag(:h1, "#{author} – #{title}")
  end
  
  def full_description
    content_tag(:p, "#{excerpt} #{description}", :class => 'description full')
  end
end

# This class also has partial templates in the directory
#   app/views/presenters/toy
# that are called
#   _cart_item.html.haml
#   _cart_item.text.erb
#
# Call presenter_for on a toy in the view or controller to get this presenter.
#
class Presenters::Toy < Presenters::Item
  model_reader :starting_age, :small_dangerous_parts
  
  def obligatory_parental_warning
    "Warning, this toy can only be used by kids ages #{starting_age} and up. Your department of health. Thank you."
  end
  
end

About

A Representer Pattern for Rails

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 100.0%