MonoRail Helper vs. ViewComponent

(Update: see Hammett’s reply post on the testability of ViewComponents)

MonoRail has two different mechanisms to perform complex logic inside of view; a Helper and a ViewComponent. How do you decide which one to use? I am going to show you how we are using Helpers and ViewComponents in our current application.

Helpers

We use Helpers as simple formatters. Our Helpers, as of now, typically contain no business logic. I don’t think this has been a good strategy for us. Why? Helpers are the easiest to test of the two alternatives. Testability makes the Helper the better choice for implementing complex business logic.

public class EmailAddressHelper
{
    public string Format(string emailAddress)
    {
        return emailAddress.Replace("@", " @");
    }
}

ViewComponent

We use ViewComponents, as of now, for more complex tasks or for tasks that require lots of markup. I am purposely showing you our worst example of a ViewComponent. PriceComponent contains lots of business logic and very little markup. Business logic is even hidden in the views that belong to this component (sales.vm is just one of 4 views for this component).

We made the wrong choice between Helper and ViewComponent in this case. We should use a Helper. Why? First, this component generates very little markup. Second, this component has lots of business rules that should have unit tests. (Should, but we don’t. Sorry, Brian. We might have UATs to cover these conditions.)

public class PriceComponent : ViewComponent
{
    public override void Render()
    {
        Listing listing = (Listing)ComponentParams["Listing"];
        string viewPrefix = "";

        if(ComponentParams.Contains("textEmail"))
        {
            viewPrefix = "text_";
        }

        if (listing.PriceUponRequest)
        {
            RenderText("Price upon request");
            CancelView();
        }
        else
        {
            PropertyBag["Listing"] = listing;
            string type = typeof(SaleListing)
                .IsInstanceOfType(listing) ?
                    "sales" :
                    "rental";

            RenderView(viewPrefix+type);
        }
    }
}

sales.vm (template for the above component)

$!Listing.FormattedDisplayPrice
#if($Region.IsShowOtherPrices)
    #if($Listing.RealEstateTax > 0)
    <br /> tax: $NumberHelper.FormatMoney($Listing.RealEstateTax)
    #end
    #if($Listing.CommonCharges > 0)
    <br /> cc: $NumberHelper.FormatMoney($Listing.CommonCharges)
    #end
    #if($Listing.Maintenance > 0)
    <br /> mt: $NumberHelper.FormatMoney($Listing.Maintenance)
    #end
#end

Guidelines

Helpers

Helpers should be used for all tasks that do not require a large amount of markup. I know, I know… How much is a large amount? I guess that depends on your tolerance for markup in “real” code. Helpers are also easier to test and are more portable than ViewComponents.

Why do I say that Helpers are easier to test and more portable?

Helpers can easily be created and invoked outside of the MonoRail framework. In our current project, we had a need to use the PriceComponent outside of MonoRail. After a day of trying, we gave up and rewrote PriceComponent as a Helper. Writing PriceComponent as a Helper allowed us not only to reuse the functionality outside of MonoRail but also allowed us to better unit test that functionality.

ViewComponents

ViewComponents should be used for tasks where large amounts of markup are required. That’s it. ViewComponents really are part of the view and they should be treated as such.

Questions/Comments are always welcome.

Advertisements

2 Responses

  1. […] Adam is certainly right on his statements about the differences between Helpers and ViewComponents, I dont quite agree about ViewComponents testability argument. There are support to test […]

  2. […] MonoRail Helper vs. ViewComponent « Adam Esterline […]

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

%d bloggers like this: