PresentFoo
PresentFoo is meant to be a very lightweight presenter library for Rails. Presenters are a great way to move logic out of views and controllers into a class which represents the state of a "view" whether that be HTML, JSON, or other. It's also a way to reduce the junk-drawer effect that happens in the /helpers directory of many large Rails applications. This is a super basic implementation and I hope to grow it over time. If you have thoughts on things that would be helpful I'd love the feedback.
Installation
Add this line to your application's Gemfile:
gem 'present_foo'
And then execute:
$ bundle
Or install it yourself as:
$ gem install present_foo
Usage
Create your Presenters
Presenters are just classes that inherit from Presenter and have a name which matches the <Model>Presenter naming convention (later we'll see how to override this).
class Book < ActiveRecord::Base
def some_model_method
"foo"
end
end
class BookPresenter < Presenter
def some_presenter_method
"bar"
end
endThe Presenter base class inherits from SimpleDelegator, which allows instances of the presenter to mirror the public interface of the object they are presenting. For example, if you have a method on your presented object or model called some_model_method, you can call it directly on the presenter and it will be delegated to the wrapped object.
Presenters also all have a hook back to the controller they were created from. For example, if you need to get access to helpers or url generators you can do so from the controller method.
class BookPresenter < Presenter
# Access to url generators
def edit_url
controller.edit_book_url
end
# Access to helper methods
def permalink
controller.create_permalink(self.title)
end
endYou can also access the request or any other contextual data that's available to the controller in this manner.
Use Presenters in Controllers
In a controller action, you simply call present or present_many which sets an instance variable that can be used in views and also returns an instance of the presenter for use in non-html responses.
class BooksController < ApplicationController
def index
books = Book.all
present_many books
end
def show
book = Book.find(params[:id])
present book
end
endapp/views/books/index.html.haml
%ul.books
- @book_presenters.each do |book_presenter|
%li= book_presenter.titleapp/views/books/show.html.haml
%h1= @book_presenter.title
%h3= @book_presenter.authorExtending Presenter Initialization
If you need to override the default behavior of a presenter at
construction-time just override the initialize or new_list methods.
class BookPresenter < Presenter
# Maps to present in controllers
def initialize(obj, arg1, arg2)
# ... do some more stuff
super(obj)
end
# Maps to present_many in controllers
def self.new_list(objs, arg1, arg2)
# ... do some more stuff
super(objs)
end
endIn controllers additional arguments passed to present or present_many will be passed to these overridden constructor methods.
class BooksController < ApplicationController
def index
books = Books.all
present_many books, "foo", "bar"
end
endChanging the Default Presenter Type
If you want to name your presenter something other than <Class>Presenter or, if you have more than one presenter for a given type you can simply pass the class you want to use as the second argument when calling present or present_many.
class BooksController < ApplicationController
def index
books = Books.all
present_many books, OtherBookPresenter, "foo", "bar"
end
endTODO
- Do something to assist with serialization scenarios
- Make PresentFoo work in non-Rails environments
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Added some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request