Skip to content

Instantly share code, notes, and snippets.

@blowmage
Created November 6, 2012 16:54
Show Gist options
  • Save blowmage/4025988 to your computer and use it in GitHub Desktop.
Save blowmage/4025988 to your computer and use it in GitHub Desktop.
Presenters in Rails, using modules

Presenters in Rails

I have bemoaned the lack of a ViewModel in Rails many times, and I prefer using Presenters to simulate a ViewModel. But it turns out there is an object that does represent the state of the view in Rails apps. Its an instance of ActionView::Base that the controller calls view_context. We don't have much control of this object, but it seems like a logical place to put our view-specific behavior.

This code is an attempt at creating Presenters using modules. The module will be mixed into the view_context object. This is very similar to how a Decorator module will be mixed into a model object, only instead of being specific to the model is it specific to the view.

This means that testing your presenter is no different than testing any other module. So relying on dependencies such as other methods or instance variables can make testing difficult.

module ActionController
module Rendering
def view_context
# Call super to get view_context from AbstractController::Rendering
_view_context = super
# Do we have a presenter? If so, mix it in.
presenter = _presenter
_view_context.extend presenter if presenter
_view_context
end
private
# Presenter constant, if it exists
def _presenter #:nodoc:
_presenter_name.safe_constantize
end
# Default naming convention for presenters. Override to change behavior.
def _presenter_name #:nodoc:
"#{self.class.to_s.sub(/Controller$/, '')}#{self.action_name.camelize}Presenter"
end
end
end
module HomeIndexPresenter
def awesomeness
true
end
end
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<p>Awesomeness? <%= awesomeness %></p>

Home#index

Find me in app/views/home/index.html.erb

Awesomeness? true

@hoffmanc
Copy link

@tute: if I am reading this correctly, it is different in that it is view-specific, versus helpers, which pollute the namespace for all views.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment