SERIES: ANTI PATTERNS AND HOW TO REFACTOR IN RUBY ON RAILS: USE FINDERS IN THE MODEL

By: Saurav

2018-02-07 21:35:00 UTC

Push All find() calls into finders on the model

Any place where you directly call finders on a model, other than inside the model itself, is a place that decreases readability and maintainability.

For example, if you wanted to create a web page that displays all the users in your web application, ordered by the last name, you might be tempted to put this call to find directly in the view code, as follows:

<html>
  <body>
    <ul>
      <% User.find(:order => "last_name").each do |user| -%>
        <li><%= user.last_name %> <%= user.first_name %></li>
      <% end %>
    </ul>
  </body>
</html>

Including the actual logic for what users will be displayed on this page is a violation of MVC.

This logic can be duplicated many times throughout the application, causing very real maintainability issues

In order to get rid of the MVC violation, you need to move the logic for which
users are displayed on the page into the Users controller;

class UsersController < ApplicationController
  def index
    @users = User.order("last_name")
  end
end

The following is the corresponding index view:

<html>
  <body>
    <ul>
      <% @users.each do |user| -%>
        <li><%= user.last_name %> <%= user.first_name %></li>
      <% end %>
    </ul>
  </body>
</html>

Most developers now realize the benefits of going one step further and moving the direct find call down into the model itself.:

class UsersController < ApplicationController
  def index
    @users = User.ordered
  end
end

And the User model contains the call to find:

class User < ActiveRecord::Base
  def self.ordered
    order("last_name")
  end
end

A better way would be to use scope which was added to ROR just for this purpose:

class User < ActiveRecord::Base
  scope :ordered, order("last_name")
end

Note All credit goes to the book I am reading: Rails Antipattern by Chad Pytel and Tammer Saleh

Owned & Maintained by Saurav Prakash

If you like what you see, you can help me cover server costs or buy me a cup of coffee though donation :)