Table of contentsClick link to navigate to the desired location
This content has been automatically translated from Ukrainian.
In Ruby, the term PORO (Plain Old Ruby Object) is often mentioned, but what is it and why is it important?
PORO: in simple terms
PORO is simply a regular Ruby object. It does not inherit from specific libraries or framework classes like ActiveRecord, ActionController, or others. A PORO is an object that:
- Is lightweight and minimalist.
- Has only the methods needed to solve a specific problem.
- Is independent of external frameworks or libraries.
Advantages of PORO
- Simplicity: PORO helps keep the code clean and understandable.
- Flexibility: You can use PORO in any Ruby project without being tied to frameworks.
- Test coverage: PORO is easy to test since they have no dependencies on a complex framework ecosystem.
When to use PORO?
- When you need to implement specific business logic that doesn't fit into models, controllers, or helpers.
- When you want to create small, standalone classes.
- When you need to reduce dependency on frameworks and make the code more modular.
PORO is important for flexible design, as it allows the creation of independent components that do not rely on frameworks like Rails. For example, imagine business logic for calculating salaries. If it is tied to ActiveRecord, its use depends on access to the database. This complicates testing and limits the ability to reuse it in other contexts, such as APIs or microservices.
With PORO, you can extract logic into a separate object that works only with input data and has no ties to external dependencies. This approach simplifies testing, enhances code modularity, and allows for easy adaptation to new needs. This makes PORO an effective tool for creating a clean application architecture.
Using PORO in Rails
Imagine that in your Rails project, there is a need to calculate the total cost of an order:
class OrderTotalCalculator
def initialize(order)
@order = order
end
def total
@order.items.sum { |item| item.price * item.quantity }
end
end
# Usage:
order = Order.find(1) # Example of an ActiveRecord model
calculator = OrderTotalCalculator.new(order)
puts calculator.total
In this example, OrderTotalCalculator is a PORO. It is separated from Rails models and controllers, making it independent and easy to test.
How to test PORO?
Due to its simplicity, PORO is easy to test using RSpec or MiniTest:
RSpec.describe DiscountCalculator do
it 'calculates the correct discounted price' do
calculator = DiscountCalculator.new(100, 10)
expect(calculator.final_price).to eq(90.0)
end
end
PORO is the foundation of clean and simple design in Ruby. They (plain objects without dependencies) help create flexible, independent components that are easy to extend, maintain, and test.
This post doesn't have any additions from the author yet.