Garnish is a Presenter / Decorator pattern for models in Rails. It gives a home to presentation level view logic that normally litters helpers and view files. Using it can help you:
- Keep helper files and views clean of if/else statements and other logic
- Better define an interface for views to interact with models
- Maintain a very familiar OOP pattern within your project directory
- Keep you controller code clean by never having to instantiate the presenters
- Handle Decorating / Presenting standard Rails relationships
Garnish Has been tested with
- Rails 3.1+
- Ruby 1.9.3, 2.0.0, JRuby, Rubinius
- ActiveRecord, Mongoid
Notes: >1.9.3
requires you to lock activesupport
and actionpack
at
>4.0.0
. For this reason we have officially dropped support for ruby
1.9.2 and earlier. Although it will most likely work without a problem.
In Rails 3, add this to your Gemfile and run the bundle
command.
gem "garnish"
A lot of magic happens with Garnish in an attempt to make things incredibly simple for you.
Create a folder in app/
called presenters. ex app/presenters/
Create a presenter matching the name of your model in your presenters folder. ex app/presenters/user_presenter.rb
Define the user_presenter
module UserPresenter
include Garnish::Presenter
end
Define methods in your presenter as regular instance methods
module UserPresenter
include Garnish::Presenter
def greeting
if last_login.nil?
"Welcome #{name}, can we offer you a tour?"
else
"Welcome back #{name}"
end
end
end
In app/controllers/application_controller.rb
add the garnish call.
class ApplicationController < ActionController::Base
protect_from_forgery
garnish
end
Or If you don't want to use Garnish application wide simply add the call into a specific controller.
The only change you need to make to start using your presenters now is to use respond_with inside any controller that has been garnished
app/controllers/user_controller.rb
def show
@user = User.find(params[:id])
respond_with @user do |format|
format.html # show.html.erb
end
end
Garnish will now find and load presenters for any instance variables you set inside your action. NOT just the ivar passed to the respond_with block.
app/views/users/show.html.erb
<span><%= @user.greeting %></span>
Garnish plays very nicely when adding view helper methods into your presenter. Just treat them like a regular method.
module UserPresenter
include Garnish::Presenter
def profile_pic
image_tag profile_pic unless profile_pic.nil?
end
end
The real reason I got down to business. If I'm using presenters in my views I probably have presenters for multiple objects.
class User < ActiveRecord::Base
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :user
end
Assuming I have presenters for both of these models
module UserPresenter
include Garnish::Presenter
end
module ItemPresenter
include Garnish::Presenter
def picture
image_tag profile_pic unless profile_pic.nil?
end
end
In my view when I'm accessing a user's items via the association what I really want is an Item extended with presenter methods not just a regular item.
Garnish handles this for us. Anytime a relationship is accessed on a garnished resource the returned resources will also be extended with their presenter methods.
<%= @user.items.first.picture %>
Works with no effort what so ever.
If you have any issues with Garnish which you cannot find the solution to, please add an issue on GitHub or fork the project and send a pull request.
To get the specs running you should call bundle
and then rake
. See the spec/README for more information.
The Ruby Moguls
Garnish was inspired by draper and the RailsCast Pro episode #287 Presenters from Scratch. See the CHANGELOG for the full list.