Follow me on Twitter!

Dont Trust This Guy why not take my word for it? A blog by Jim Jeffers

Using Presenters in Rails

Sitting thrugh my first tutorials session at RailsConf we’ve come across an interesting discussion about the philosophy of using the ‘Presenter Pattern’ to refactor code in your applications controller.

What the presenter initially did was build out a traditional presenter class to extend the model and provide two methods to find possible status and priority objects from the database. This requires the author to delegate class methods from the model that the Presenter class could use. It also requires us to wrap any instance variable of the child object in the presenter class before we pass it to the view.

class StoryPresenter

  def initialize(story)
    @story = story
  end

  delegate  :id, :class, :errors, :to_param, :new_record?,
            :to => :@story

  def possible_statuses
    @statuses = Status.find(:all).map{ |s| [s.name, s.id] }.unshift []
  end

  def possible_priorities
    @priorities = Priority.find(:all).map{ |e| [e.name, e.id] }.unshift []
  end

  def method_missing(name, *args)
    @story.send name, *args
  end

end

And then the implementation in the controller looks something like this:

def create
  story = @project.stories.build(params[:story])
  respond_to do |format|
    format.js do
      @story = StoryPresenter.new story
      render :action => "stories/new" unless story.save
    end
  end
end

A member in the audience suggested that instead of treating the presenter as a traditional presenter object we simply write it as a module. Then we no longer would have to delegate the methods from the model and instead of wrapping any instance variable of the child class we could just extend it. The argument for this is clear. It’s less code, and it’s more flexible.

module StoryPresenter

  def possible_statuses
    @statuses = Status.find(:all).map{ |s| [s.name, s.id] }.unshift []
  end

  def possible_priorities
    @priorities = Priority.find(:all).map{ |e| [e.name, e.id] }.unshift []
  end

end

And then the implementation in the controller looks something like this:

def create
  @story = @project.stories.build(params[:story])
  respond_to do |format|
    format.js do
      @story.extend StoryPresenter
      render :action => "stories/new" unless @story.save
    end
  end
end

However, the arguments against using a presenter as a mixin are more philosophical. If we’re using the presenter pattern we should encapsulate only what we need the view to use explicitly to prevent logic leaking into the view or the controller by other authors. By treating the Presenter object as a class and explicitly delegating the model methods we do just that. To utilize further methods of the model we would need to return to the presenter object and extend it there as opposed to just sliding extraneous logic into our controller or view.

One Response to This Article.

  1. Arthur Says:

    I would much more prefer having the presenter object as a class rather than a mixed in module.
    First of all, the class is isolated and thereby much easier to test.
    Second of all, if you have two models in a controller you would end up in the same situation as without the presenter object. You would have to instantiate and extend all the models in every action in contrast to the presenter class where you would have the same instance variable in all of the actions.
    Interesting idea though!

Leave a Reply

Meta Information

This post was filed under code and tagged with: , , , .

This Post as a Feed

The content of this post and it's comments can be subscribed to as an RSS feed.

DontTrustThisGuy.com and all contents copyright 2003-2007 by Jim Jeffers, unless otherwise noted.Written in valid XHTML and a participant of XFN while being powered by WordPress
Contents under Creative Commons License. Visual design, layout and Cascading Style Sheets may not be reused without permission.
Entries (RSS) and Comments (RSS)