My experience with Presenter Pattern

Default MVC layers handles one model, one form mode pretty well, but in reality, a lot of forms are not that simple. There are two classic examples:

  1. Multiple models are created/updated in one form
  2. One model is created/updated in one form, but in several different ways

When these scenarios happen, MVC framework becomes awkward. We have to either leak business logic into controllers, even views, or put view logic into models, or both. In this post, I want to talk about how to use Presenter Pattern to avoid putting view logic into the models.

Basically Presenter is one layer sitting between Controller and View layer, which should include all of your view logic. The first advantage we gain is that we can unit test view logic easily. Secondly, we can move all helper methods into presenters so that we can have a more elegant way to implement these methods. The third and the most important advantage we gain is that now the model is free from view logic, make its intention much more clear.

Now let’s see an example.

I have a model House, on creation form of House, there are some fields about this house. Some of them are required, some of them are optional. The form has two submit buttons, if a user click on button 1, she will become the owner of this house; if she clicks on button 2, she assigns another person to the owner of this house. When she assigns another person, she needs to pick a person before assigning, for the sake of simplicity, let’s assume she can pick a person from a drop-down list with all eligible person names.

Now if she clicks on button 1, she doesn’t need to choose any person from the drop-down list. But if she clicks on the button 2, she must select a person from that list, and if she doesn’t choose a person, she should get an error message to prompt her to do so. So we see a validation here, but this validation is totally view-specific, nothing to do with either House or Person models. In this situation, a presenter is a natural place to put this logic.

To implement this validation, one tool you absolutely need is the Validatable gem. Once a class includes a Validatable module, it has a lot of ActiveRecord-like validation logic such as validates_presence_of.

I will name my presenter after the form, in this case, NewHousePresenter, but if I know I will reuse this form in edit/update, I will simply name the presenter as HousePresenter.

Inside the presenter, I can have:

	validates_presence_of :owner_id, :if => lambda {|presenter|presenter.assign_owner?}

How to implement assign_owner? is just a matter of implementation of your view, I like to just set a hidden field with value “assign_owner” when clicking on the button 2 and “take_owner” when clicking on the button 1. Then the assign_owner? is just checking if the hidden field is string of “assign_owner”.

Isn’t it cool?

In my previous post More on form_for(@non_arb), I showed a trick to get polymorphic routes working so that the form can be

<% form(@presenter) %>

In my HousePresenter, I can just say:

	polymorphic_routes_for :house, :create_path => "house_owner_path", :update_path => "house_owner_path"

Not only is it for the sake of coolness, but also for the simplicity of the view and easiness to use the form in both create and update actions.

In my Presenter class, I also have an initialize declared as:

def initialize(params={})
  params.each_pair do |key, value|
    instance_variable_set("@#{key}", value)
  end
end

All this does is just blindly set instance variables for all params passed in. The reason for doing this is that I can easily setup a presenter for unit testing. The subclass of Presenter should implement a build class method to take params from the controller, and parse it into a hash that is sensible to the presenter and initialize. So the “constructor” remains simple for convenient construction while build can do complex logic that can be unit tested.

A build method can look like:

def self.build(house_params = {}, operation = "take_owner")
	
	presenter_params = {:house => House.new(house_params), :operation => operation}
	HousePresenter.new presenter_params
end

After all this, my HousesController#new and create can be as simple as:

def new
	@house_presenter = HousePresenter.build
end

def create
	@house_presenter = HousePresenter.build(params[:house], params[:operation])
	if @house_presenter.valid? && @house_presenter.house.save
		redirect_to(@house_presenter.house)
	else
		render :new
	end
end

Don’t they look like controller actions again? You can infer the edit/update code from here fairly easy.

But for the perfectionist, this line:

if @house_presenter.valid? && @house_presenter.house.save

is a little bit smelly. Bigger thing is: if the creation/update require more then just a save, then we need something else. I almost want to be able to say:

if @house_presenter.save!
...

and in save! I do whatever I need. I actually did that and Marcel Molina looked ultimately confused and I agree with him: Presenters are not meant for business transactions. hmm. well, it’s a long enough post, I would like to talk about this issue in my next post, if it eventually comes out.

About these ads

~ by Yi Wen on April 6, 2008.

One Response to “My experience with Presenter Pattern”

  1. […] took time to read more about the presenter pattern today. I came across an interesting post which included a few statements that were very […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: