Keeping Domain Logic Out of Views
A typical Rails application includes domain logic and presentation logic. Domain logic – often called “business logic” – includes algorithms, calculations, rules, etc. applicable to your models.
class Employee < ActiveRecord::Base def recently_hired? Time.now.months_ago(1) < self.hire_date end end
Presentation logic, on the other hand, affects the rendering of elements in the user interface.
(/employees/_employee.html.erb):
<% div_for employee do %> <% if employee.recently_hired? %> ...employee details... <% end %> <% end %>
The problem is when domain logic leaks into Views and begins to take on the responsibility of presentation logic.
<% div_for employee do %> <% if Time.now.months_ago(1) < employee.hire_date %> ...employee details... <% end %> <% end %>
The above rule may change, perhaps Human Resources decides “recently hired” includes anyone hired this past quarter. So in this case, a change in domain logic would require you to change your View code. Further, if you needed to evaluate this condition in other Views, you’d have unnecessary code duplication that now needs to be maintained in more than one spot.
Looking back at the second code snippet, you may be thinking, doesn’t the following smell like domain logic?
<% if employee.recently_hired? %> ...employee details... <% end %>
And what happens when requirements change, and now we have to also consider employment status…
<% div_for employee do %> <% if employee.recently_hired? && employee.full_time? %> ...employee details... <% end %> <% end %>
Again, it seems like changes to domain requirements would require us to maintain the View. This may not seem like a big deal when you’ve got a handful of templates, but in a larger application, where there may be a few developers actively working on the project, these things matter.
So why not handle it by pushing back into the model and doing something like
class Employee < ActiveRecord::Base def displayable? self.recently_hired? && self.full_time? end end
With the above, we’ve now attached presentation logic to the model. Whether something is “displayable” should not be the concern of a model, especially when it’s not aware of the context the data is being used.
Fortunately, Rails Helpers allow us to pull anything that resembles domain logic out of the View completely but still influence what the user sees in the View:
module EmployeesHelper def display_employee(employee) if employee.recently_hired? && employee.full_time? content_tag(:div, "#{employee.full_name}, #{employee.hire_date}") end end end
…as well as simplifying the View:
<% div_for employee do %> <%= display_employee(employee) %> <% end %>
Several use cases, in which helpers are handy for evaluating a model and generating presentation logic, include:
- Dynamically inserting CSS selectors into markup
- Evaluating whether text should be hyperlinked
- Changing the layout (markup) of the screen
About this entry
Posted: Friday, June 20th, 2008 at 1:56 am
- Author:
- Phil Misiowiec
- Category:
- Patterns
- Tags:
- basics, mvc, ruby on rails
- License:
- Creative Commons

No comments
Jump to comment form | comments rss | trackback uri