Implementing Services in Rails

I’ve been struggling with MVC for a while. There seems to be a problem that I can’t quite put my finger on.

Models describe data.
Controllers route data.
Views show data.

Where do things that don’t fall into those categories go? I’m working on a product right now that needs a search engine. I started working on it, but quickly came back to my doubts about MVC. A search engine is not the model. It has to search through multiple tables. The logic for it is going to be a little big. Putting it in a controller seems like a miss use of the controller as well. Where should it go?

The answer:

Services are amazing. It’s the fourth corner stone of MVC. It should be called MVCS. Everything becomes beautiful and makes sense as you implement services. I’m going to go over what I did from start to finish to on that search feature.

Make a search feature that reads searches different or multiple tables based on the first character in the string. @ searches the user table. # searches the posts table. The search field is stored in the nav bar and routes to Users#search. This is the Users#search method inside the UserController:

  def search
    @q = params[:query]
    @results =
    render :"/users/index"

That’s a clean looking controller! There’s a trick to it though. “” is the service. First create a folder called “services” in the “app” directory. From there we’re going to make a file that shares the name of the class of the service we’re creating. In my case, it was search.rb. Here’s a look at the file structure and how to set-up services in a Rails app:

Screen Shot 2015-04-14 at 3.01.32 PM


Once we’re in “services/search.rb,” it becomes pretty easy to implement the search function. To account for upper and lower case characters, we added a column to our tables for a search field.

class Search

    if query[0] == "@"
      clean_search = "%#{query[1..-1]}%".downcase
    elsif query[0] == "#"
      clean_search = "%#{query[1..-1]}%".downcase
      clean_search = "%#{query}%".downcase

  def self.search_user(q)
    User.where("search_handle LIKE ? or name LIKE ?", q, q) 

  def self.search_tag(q)
    Post.where("search_post_content LIKE ?", q) 

  def self.search_all(q)
    results = []
    results[0] = Search.search_user(q)
    results[1] = Search.search_tag(q)

That feels nice and clean. We have a class that searches. If we need to adjust details about the search, we go to the search service and adjust. It’s not the controller. It’s not the model.

Services are a very important part of the MVC idea. Services are a great way to spread out the logic and reduce complexity.


Leave a Reply

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

You are commenting using your 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