In this beginner-friendly series, we’re looking at AntiPatterns, which—as the name implies—represent pretty much the opposite of design patterns. They are discoveries of solutions to problems that you should definitely avoid.
In this article we’ll focus on the main View AntiPattern—PHPitis—and work through a couple of techniques to keep your views lean and mean. Having tons of Ruby code in your views is not only nasty but often plain unnecessary.
Topics
- Rails Views
- PHPitis
- Extracting Helpers
- Helpful Helpers
- Forms
- Partials
- Conditional Content
- Semantic Markup
Rails Views
Rails comes with ERb (Embedded Ruby) out of the box, and I think it’s not necessary to throw in cool view-rendering engines like Slim for our examples for now. If you think “convention over configuration” mostly applies to the model and controller layers, you are missing out on a lot of the goodies that make working with Rails so speedy and progressive. Taking good care of the view layer includes not only the way you compose your markup but also CSS/Sass, JavaScript, view helpers, and your layout templates. Viewed from that angle, it becomes a bit deeper than you might think at first. The sheer number of technologies which can be involved in creating your views suggests that care should be taken to keep things neat, clear and flexible.
Since the way we write markup and styles is a lot less constrained than domain modeling, you want to be extra cautious to keep things as simple as possible. Maintenance should be pretty much your number one priority. Since redesigns or design iterations can be more frequent than extensive changes to your model layer, preparing for change gets a whole new meaning when it comes to your user-facing layer. My advice: don’t necessarily build for the future, but also, by all means, do not underestimate the rate of change—especially if you have one of those “idea guys” who knows jack about implementations on the team. What I like about Rails’s approach towards views in MVC is that it is treated as equally important, and the lessons learned from the model domain were incorporated into the view—whenever possible and useful. Other frameworks seem to agree, since they integrated a lot of these ideas pioneered by Rails.
Since the last article was a bit more extensive, I chose this topic as a small breather. The following articles about Rails controllers and testing are again bigger in size. The AntiPatterns for views are not that many, but they are nevertheless equally important. We’ll focus on the main one, PHPitis, and work through a couple of techniques to keep your views lean and mean. Since the view is your presentation layer, maybe you should be especially careful to not create a hazardous mess. Let’s get to it!
PHPitis
Why do we have MVC in the first place? Yes, because the separation of concerns seemed like the most reasonable thing to do. Sure, the implementations of this idea vary a bit here and there, but the overall concept of having distinct responsibilities for each layer is the core motivation for building robust applications. Having tons of code in your view layer might not be alien to developers coming from the PHP side of things—although I hear their frameworks have caught up already (heavily influenced by things like Rails?)—but in Ruby-land these things have long been a loudly voiced AntiPattern.
The obvious problems like mixing responsibilities and duplications aside, it simply feels nasty and lazy—a little stupid too, to be frank. Sure, I get it, when you develop much within a framework, language or whatever ecosystem, it’s easy to become complicit or numb towards things like that. What I like about the people pushing Ruby is that these things seem to have a lot less weight—that might be a reason why innovating never seemed to be a problem within the community. Whatever works best wins the argument, and we can move forward.
So is this a whole section dedicated to bashing PHP? Not at all! In the past, PHP apps had the reputation of having weak separations between models, views and controllers (maybe this was one of the core reasons why people felt writing apps with Rails was much more appealing). Having single files with code for all three layers didn’t seem that sexy. So when we stuff tons of Ruby or domain code into our views, it starts to look like the dreaded PHP style of structuring things—PHPitis. Only a few things are as bad as this when it comes to developing web apps, I feel. When you care about happy developers and your own future sanity, I can’t see why anyone would go down that road—there’s only pain ahead, it seems.
Rails offers a lot of goodies to minimize code in the view as much as possible. You must learn the ways of helpers, layouts and preprocessors in order to achieve a cleaner view. A simple rule of thumb is to keep domain logic out of your views—no shortcuts!
The price to pay for being lazy on this is hard to overestimate. The Ruby code that must be in the presentation layer should be as little and as simple as possible, as well as intelligently organized. Your reward will be code that is a joy to extend and to maintain, and new team members will also have an easier time wrapping their heads around the new codebase. As a bonus, neat freak designers who code also won’t be angry and hide rotten food in your salad if you keep tons of Ruby code out of their markup.
Helpful Helpers
Knowing the myriad of helper methods in Rails will significantly improve the quality of your presentation layer. Not only will it clean things up and inject the occasional speed boost in productivity, but more importantly it helps you fight PHPitis.
The thing that you should appreciate about these helpers is that they represent extractions from commonly needed code. Instead of reinventing the wheel, when in doubt, check if there isn’t already a helper around that solves your issue in the view—the same goes for Models and Controllers as well, of course.
Here’s a list of helpers you should look into pretty much right away:
-
- Other helpers for forms.
-
-
-
- And writing your very own, of course.
Forms
Let’s have a look at <pre class="brush: form_for"></pre> first. I know forms are a little bit boring and not that sexy for a topic, but I highly encourage you to read up on them to familiarize yourself with the finer details. It’s important to understand how they work. I remember often just glancing over them without giving them much attention. Sure, you can get them to work quite easily without understanding what’s going on under the hood. In the future, I might take the time to write a complete article on them. In the meantime, I highly recommend that you spend a little time checking the documentation–at least you‘ll appreciate how convenient Rails makes it to deal with form stuff.
The Ugly
The example below shows you the HTML of a little form we need for creating agents. It only accepts three parameters as input: <pre class="brush: name"></pre>, <pre class="brush: number"></pre> and <pre class="brush: licence_to_kill"></pre>. A lot of code for this little task, actually. The <pre class="brush: authenticity_token"></pre> comes from Rails–it’s a security thing that protects the app from “cross-site request forgery”.
some.html.erb
1 |
|
2 |
Writing a form by hand is not only lengthy but error prone as well. Also, if we approached it that way, we’d also have to solve the issue with the varying routes and CSS classes that we might need for creating a new object and updating an existing one—in effect, we would need to duplicate forms to create and edit records. As you’ll see soon, Rails meets you more than halfway on that. Verdict: however you put it, the manual approach is nasty and lacks convenience.
The Bad
We could go down the following road, which does not make perfect use of conventions in Rails. Heads up, don’t do it. It basically shows that you’re not handling the available tools to your advantage and you are duplicating the form for <pre class="brush: new"></pre> and <pre class="brush: edit"></pre> actions.
some.html.erb
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
What happens here is that the form builder carries the model you need for the form.
1 |
|
2 |
|
3 |
|
4 |
Behind the scenes, the line above gets expanded into the following:
1 |
|
2 |
|
3 |
|
4 |
The <pre class="brush: form_for"></pre> method takes a couple of arguments:
- a symbol or a string for specifying the object
- a <pre class="brush: url"></pre> hash
- an <pre class="brush: html"></pre> hash
- a <pre class="brush: namespace"></pre> hash
The url hash is for specifying the routing options. That means that you can manually specify to which routing path you submit the form—named routes come in handy with this. This style is called the “generic way” because you need to manually configure the <pre class="brush: form_for"></pre> call.
Why is this solution suboptimal? Because we want to keep business logic out of our Views and Controllers as much as we can. A side effect of that is that we need to change fewer parts when needed.
HTML
1 |
|
2 |
In case you missed it, this approach did not provide us with ids and classes for the <pre class="brush: form"></pre> tag automatically. The ones for <pre class="brush: input"></pre> tags, however, were generated for you. We’ll fix that in a minute. Just know what you can get for free and that you probably should use this to your advantage. If you need something different or an additional namespace, you can use the <pre class="brush: html"></pre> hash or the <pre class="brush: namespace"></pre> hash to specify things a bit more.
some.html.erb
1 |
|
2 |
|
3 |
|
4 |
HTML
1 |
|
2 |
Not bad! Now the <pre class="brush: form"></pre> tag has the specified class and id—whatever makes your blood flow—and the <pre class="brush: input"></pre> tags are namespaced with <pre class="brush: mi6"></pre>. Almost there.
The Good
This one is called the “resource-oriented style” and has the least amount of Ruby you need to write in your views. With that approach, we want to rely on automated resource identification. Rails figures out which routes it needs based on the object itself. Not only that, it gives you a different HTML output for creating a new object or for editing an existing one. Behind the scenes, Rails just asks the object if it already exists and acts accordingly.
Creating forms this way is a clever use of conventions and helps avoid duplication. One line and all the heavy lifting is done for you.
some.html.erb
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
Much better, isn’t it? Now we get exactly what we need for both existing and new objects. Also, we didn’t need to add text to our submit button. Rails took care of that and also adapts to new or existing objects.
HTML for a New Object
1 |
|
2 |
HTML for Editing Objects
1 |