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
end
The 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
end
You 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
end
app/views/books/index.html.haml
%ul.books
- @book_presenters.each do |book_presenter|
%li= book_presenter.title
app/views/books/show.html.haml
%h1= @book_presenter.title
%h3= @book_presenter.author
Extending 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
end
In 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
end
Changing 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
end
TODO
- 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