Facade Pattern on Rails

For fun and profit

Open any average rails project. Take a quick look at models, views and controllers. You will probably see the following:

  • views are responsible for presenting data to the user,
  • models are responsible for data manipulation,
  • controllers are responsible for everything else.

Poor controllers nowadays receive about a dozen different responsibilities. One of the responsibilities that is being thrown at the controller is to prepare the data so it can be presented to user. Today I want to talk about a way to remove this responsibility from controller.

Starting point

Lets assume we have a controller that looks like this:

# app/controllers/customers_controller.rb
class CustomerController < ApplicationController
before_filter :set_customer, only: :show
 def show
@new_contact = @customer.contacts.new
@recent_contacts = @customer.contacts.last(5)
@notifications = @customer.notifications.order(‘user_id DESC’)
end
 private
def set_customer
@customer = Customer.find(params[:id])
end
end

Controller is already messy at this point and we are only getting started with our application; we are already setting four global variables, receiving requests and dispatching responses. Imagine what it will look like once we add more functionality like authorising user requests or maybe logging her actions — it will bloat the controller code even more and make it hard to maintain and read.

Facades

To remove the responsibility of preparing the data for the view I am using Facade pattern.

Lets start off by creating a facade (I have a /facade/ folder inside my /app/ folder where I keep all of my facades):

# app/facades/customer_facade.rb
class CustomerFacade
attr_reader :customer
 def initialize(customer)
@customer = customer
end
 def new_contact
@new_contact = customer.contact.new
end
 def recent_contacts
@contacts ||= customer.contacts.last(5)
end
 def notifications
@notifications ||= customer.notifications.order(‘user_id DESC’)
end
end

Now we can reduce our controller down to:

# app/controllers/customers_controller.rb
class CustomerController < ApplicationController
before_filter :set_customer, only: :show
 def show
@customer = CustomerFacade.new(@customer)
end
 private
def set_customer
@customer = Customer.find(params[:id])
end
end

And inside our view we will call for our facade:

<%= render @customer.notifications %>
<%= render ‘contacts/form’, contact: @customer.new_contact %>
<%= render @customer.contacts %>

Final thoughts

There are some drawbacks to this approach. The biggest one is probably the fact that we are introducing another layer of abstraction to our application. But it is a price I am willing to pay to keep my code clean and maintainable.

Also this approach is not a silver bullet for a small application — if your code is a mess at this point then you are probably doing something wrong. But once your application starts growing and views get more and more complex you would probably find the pattern useful.

Show your support

Clapping shows how much you appreciated Ruslan Yakhyaev’s story.