Post
🇫🇷 Français

Clean code with poros

The PORO (Plain Old Ruby Object) concept allows you to create a class with a single responsibility. Let's apply this to Ruby on Rails!

Introduction to PORO

When developing web applications with Ruby on Rails, there is a tendency to put too much logic into controllers or models. This approach neglects a fundamental principle of Clean Code: the SRP (Single Responsibility Principle). When a class is responsible for multiple behaviors, the application becomes challenging to maintain, test, and extend with new features.

Use case

Let’s imagine an application where you have a User model:

1
2
class User < ApplicationRecord
end

A user has a role attribute that can be: admin, premium, or guest. The admin should be able to:

  • Delete a user, except for another admin.
  • Change a user’s role from guest to premium.

To adhere to the SRP principle, we cannot create these methods in the User model, as its sole purpose is to manage users regardless of their roles. Therefore, we will create a PORO to handle admin actions.

First, create an app/models/user/admin.rb file. For clarity, we will place the Admin class in the User module:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module User
  class Admin
    attr_reader :admin
  
    def initialize(user)
      @admin = user
    end
    
    def delete_user(user)
      user.destroy! unless user.admin?
    end
    
    def update_to_premium(user)
      user.update!(role: 'premium')
    end
  end
end

To use a PORO in a controller, you first need to initialize the instance.

1
2
# current_user is the connected admin 
@admin = User::Admin.new(current_user)

Then you can call its methods:

1
2
3
4
5
# user_to_delete is an instance of a User
@admin.delete_user(user_to_delete)

# user_to_update is an instance of a User
@admin.update_to_premium(user_to_update)

Conclusion

Using POROs in a Ruby on Rails application ensures:

  • Adherence to the SRP principle
  • Logical separation of methods
  • Improved code readability
  • Better maintainability of the application
  • Easier test coverage for the entire project
All rights reserved by the author.