Petro Yakubiv
Mar 20, 2018 · 8 min read

In this post, I will share some patterns I use when developing Ruby on Rail applications. This is something other developers don’t always do — especially younger developers and those switching from other technologies. These principles help me a lot, and if you’re not using them now, I hope you’ll give them a try. I’ll introduce each topic and provide some resources I found useful when first learning about them.


Let’s start with unit testing. If you want to be confident that your application works as expected, you have to write tests. Rails comes with Minitest as a default test framework, but I prefer to use RSpec.

Test-driven development, or TDD, is the workflow you use when you create tests and add functionality only as each test is passed successfully. At first glance, it seems like a waste of time, because you have to decide what to test, write the test, etc. But eventually you’ll see the benefits of testing, especially in how fast you can work. Testing makes adding new features, modifying existing code, or refactoring a breeze. You don’t have to go to the browser after each change to see if it works.

Here are four resources for learning about TDD.


Rails encourages the idea of DRY: an acronym for Don’t Repeat Yourself. The idea behind it is simple: whenever possible, reuse as much code as possible rather than duplicating similar code in multiple places. This saves time, reduces errors, and keeps your code clean.

Joel Abrahamsson wrote an in-depth post about the merits of DRY;

Sandi Metz’ Rules

Sandi Matz is a very well-known Ruby software engineer. She is an author of canonical books such as Practical Object-Oriented Design in Ruby and 99 Bottles of OOP. Here are some of her rules that have been especially helpful to me.

1. A class should not be longer than 100 lines.

You can attach specific behavior by including or extending modules into a class. It is a good way to keep classes short and explicit. Here are some links that explain the difference between prepend, include, and extend modules.

2. Methods may not be longer than five lines.

The fewer lines in a method, the less complex it looks, and as a result, it has self-documenting code. The name of the method should clearly describe what it does. The five-line rule applies to if-else statements; implementing them requires at least five lines. It’s often difficult to describe a method in fives lines. That’s ok; just keep it as short as possible. Here’s a good reference on writing methods:

3. Pass no more than four parameters to a method.

Too many parameters results in :

  • Complexity
  • Less efficient changes
  • More difficult testing due to the large amount of setup

The fewer parameters, the simpler the method.

4. An action in controller can have only one instance variable.

With only one instance variable, you retain better control and are less likely to overwrite it. Your templates are cleaner and more readable.

There’s much more to learn from Sandi. Go to Sandi Metz’ Rules For Developers.

Extract method

Each method needs a name that explains its purpose. You are writing code for humans. If your method has an explicit names, new developers understand its purpose faster and easier. It’s good practice to create a new method for each purpose; that way, it’s much easier to debug and test.


SOLID is an acronym for design patterns in programming. It stands for

Single responsibility


Liskov substitution

Interface segregation

Dependency inversion

Michael Feathers of Object Mentor International created SOLID, and compliance with these rules leads to more flexible, maintainable, and understandable code.

N+1 Query

N+1 is a problem of ORM (ActiveRecord) that can impact performance and increase the numbers of queries to the database. It appears when you need to fetch data from several related tables. Here’s an example:

class User
has_many :posts
class Post
belongs_to :user
posts = Post.last(10) { |post| }

The code above will generate 11 queries to the database. The first query fetches the last ten posts, and ten more queries for user name of each post. But with Rails, we can easily be more efficient.

posts = Post.includes(:user).last(10) { |post| }

After we have added includes(:user), we will have only two queries. You can find more in-depth explanations in these articles.


Memoization is the process of caching the results of a time-consuming method. When you call the method the second time, the cached result returns.

Memoization saves effort by using the results of a computation repeatedly. For example, say you have to create a report for each company in your app. Let’s imagine a table with company names in a header and company activities grouped by day as a table body.

class CompaniesController  def index    @companies ||= Company.all  end  private  helper_method :grouped_by_day_activities  helper_method :activities_count  def grouped_by_day_activities    @grouped_by_day ||= Activity.all.group_by(&:day)  end  def activities_count  @activities_count ||= do |day, activities|    grouped_by_company_activities_count =     activities.group_by(&:company_id).map do |c_id, activities|      [c_id, activities.count]    end.to_h    [day, grouped_by_company_activities_count]  end.to_hendend# activities_count =># { ‘1/1/2018’: { 1: 10, 2: 6, 3: 9 },# ‘2/1/2018’: { 1: 5, 2: 4, 3: 7} }…../companies/index.haml%table  %thead    %th Date    - @companies.each do      %th=  %tbody    - grouped_by_day_activities.each do |day, activities|      %tr        %td= day        - @companies.each do |company|          %td= activities_count.fetch(day).fetch(, 0)

In this case, each method in the controller uses memoization. Memoization defines with a ||= (or eq) sign. Let’s begin with the @companies variable. The first time it performs in the table’s header, and the second time in the body. So we’ve already reduced one query.

Another method, grouped_by_day_activities, returns grouped by day activities. The first time, it appears in the table body, and the second time, in activities_count method.

activities_count method returns a hash grouped by day and company_id activities count; it is also memoized. It is the most executable method and performs in each cell of table. Imagine how long it will take if you make a request to the db from each cell. Instead, you just re-use the results of one operation. You can also dynamically memoize methods with meta-programming.


Authentication is a mechanism of verifying identity and permissions that allows you to hide sections of application from guest users. I highly recommend using the devise gem.

Rails Authorization

Authorization is verifying that a user has permission to perform an action. Let’s imagine we have three different types of users on our application: admin, guest, and manager. We want only admin and managers to be able to edit posts, so we wrote these conditions:

if user.role == ‘admin’ || user.role == ‘manager’= link_to ‘Edit post’, edit_post_path(post)

We have a ton of the same conditions across the app. Suddenly, we decide to allow our guest users to edit their posts. Now we have to go through each file and change conditions, like this:

if user.role == ‘admin’ || user.role == ‘manager’ || user.role == ‘guest’ 

With pundit gem, our application will have a new folder, policies, which will host the permissions logic of each entity. Let’s see the user policy file:

class UserPolicy  def can_edit_post?    user.role == ‘admin’ || user.role == ‘manager’ || user.role == ‘guest’  endend

If statement will look like:

if policy(user).can_edit_post?
= link_to ‘Edit post’, edit_post_path(post)

It will be much easier to modify one line of code in the user policy class the next time we decide to change our logic. It saves a lot of time and prevents permission bugs. Learn more in these links:

Seven patterns to refactor Rails app

Refactoring is a process intended to make code faster, more readable, and more easily maintained without changing a behavior.The articles below present the most common patterns of refactoring in Rails applications.

Background jobs

Everyone understands the need for speed, and this tip is essential for writing code that gives responses as fast as possible. A background or asynchronous job performs time-consuming tasks outside the main process workflow. Usually, when an application receives some message from the external world, it tries to return a response within a couple of milliseconds. But sometimes, when the action has to accomplish something big and time-consuming, asynchronous jobs is the way to go. They perform the process as usual, but in a different thread. That is how you can deal with complex operations without timeouts. One of the most popular gems for background jobs is Sidekiq.


Here’s a very cool screencast to share with you: rubytapas. There are a lot of small videos covering intermediate to advanced techniques and concepts, programming and refactoring principles, and so on. Thanks to Avdi Grimm!


When I started my Ruby on Rails journey, studying resources like those I’ve shared here helped me learn how to use Rails and accomplish the tasks I needed to do.

Support from experienced developers is vital. I was lucky to have a mentor, and his knowledge, support, and patience helped me learn everything I know today. I still have a lot to learn, but I feel obligated to the Rails community, and want to share my knowledge with the web-world just as my mentor did with me.

When you’re learning something complex, the most important thing is to not give up. I had a terrible time learning Rails. Every morning I woke up thinking, “I know nothing and I am useless piece of sh*t.” Sometimes I spent the whole day trying to accomplish one task that I knew could be solved in five minutes. But I did not give up, and after a couple of months I gained a far better understanding of how things work together.

Stay patient and believe in yourself!

Happy coding. :)

Original resource:

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade