facebook Clutch Top custom software development companies

2 Simple technics to refactor Ruby on Rails

2 Simple technics to refactor Ruby on Rails
Average rating: 0
(0 votes)

Thanks! You’ve rated this material!

Refactoring is a necessary process in any Ruby on Rails application

Without it your app will quickly become time expensive to support. Also, your architecture will get more and more messy (and with messy code you can’t deliver new things fast and guarantee good quality) – unneeded relationships which cause spaghetti code and mess of callbacks for example and so on. The Rails Way doesn’t scale. It works well when your project is small and quite simple. While you grow you need to use more complex and tricky things to keep project ‘in shape’.

There are two ways to do refactor Ruby on Rails apps: by changing small pieces of code and making bold architectural complex changes. For sure, the second way is more preferable.

Changing separate small code pieces is better than nothing but it can have zero effect in general, just don’t reinvent the wheel in refactoring. There are some common principles of refactoring used by RoR community and I am sure that it will help you in 99% of situations.

In this article I will show you only two simple technics to refactor Ruby on Rails apps that can make big difference. We will start from controllers, you can use them for many things – communicate with models, take care of HTTP request parameters processing, set up shared state across your actions, render views, choose among different response formats based on the content type etc., but it will be much better if you move some business logic pieces out of controllers. Why? To stay lean and slick. Form and Service Objects will help us with this task.

Form object

They are good for moving away the params processing responsibility out of the controller. In Form object you can check and validate everything related to form – presence of some fields, their length and content type. You can use Virtus and ActiveModel libraries here, which will simply wrapping params object from controller.

Example of Form Object:

class OrderForm
  include ActiveRecord::Validations
  include Virtus.model

  attribute :title, String
  attribute :content, String

  validates :title, :content, presence: true
  validates :title, length: { minimum: 5 }

  def persisted?
    false
  end

  def validate!
    raise ValidationError.new(errors: errors) unless valid?
  end
end

Example of Controller:

class OrdersController < ApplicationController
  def create form = OrderForm.new(params)
  form.validate!
  # your logic here.
  rescue ValidationError => err
  # …
  end
end

Service Object

It is a very good idea to combine Form Object with Service Object. While form objects are extracting the input handling responsibility from your controllers, service objects are all about extracting business logic out of them.

class SubmitOrder
  def initialize(order_mailer)
    @order_mailer = order_mailer
  end

  def call(form)
    Order.create!(form.attributes).tap do |order|
      order_mailer.published_order_mail(order).deliver_later
    end
  end

  private
  attr_reader :order_mailer
end

With the above 2 objects our controller will look like this:

class OrdersController < ApplicationController
  def create
    form = OrderForm.new(params)
    submit_order = SubmitOrder.new(OrderMailer)
    @order = submit_order.call(form)
  end
end

Much better, isn’t it? Now you can easily test separate objects, add logic and don’t be afraid of getting unreadable messy code.

So, start using the described techniques, give them a chance and you’ll be satisfied with the results. 😉63003111

Rate this article, if you like it

Thanks! You’ve rated this material!

Got a project? Let's discuss it!

*By submitting this form you agree with our Privacy Policy.

Mailing & Legal Address

Syndicode Inc. 340 S Lemon Ave #3299, Walnut CA, 91789, USA

Visiting & Headquarters address
Kyiv Sofiivska 1/2a, 01001, Kyiv, Ukraine
Dnipro Hlinky 2, of. 1003, 49000, Dnipro, Ukraine
Email info@syndicode.com
Phone (+1) 9035021111