Decorators Presenters and Commands in Ruby on Rails
π Mastering Decorators, Presenters, and Commands in Ruby on Rails
Ruby on Rails (RoR) is a framework that thrives on clean and maintainable code. But have you ever wondered how to better separate concerns, handle presentation logic, or encapsulate business logic efficiently? Today, we dive into Decorators, Presenters, and Commands β powerful patterns that will elevate your Rails applications! π
π Decorators: Adding Behavior without Changing Objects
A Decorator is used to add extra behavior to an object dynamically, without modifying its original class. Itβs particularly useful for organizing view-related logic.
Example:
# app/decorators/user_decorator.rb
class UserDecorator < SimpleDelegator
def full_name
"#{first_name} #{last_name}"
end
def formatted_join_date
created_at.strftime("%B %d, %Y")
end
end
# Usage in Controller
@user = User.find(params[:id])
@decorated_user = UserDecorator.new(@user)
Hack:
- Use the
Draper
gem for a more streamlined approach to creating decorators. It integrates seamlessly with Rails:
# Gemfile
gem 'draper'
class UserDecorator < Draper::Decorator
delegate_all
def display_name
object.name.upcase
end
end
# Usage
@user = User.find(params[:id]).decorate
Best Use:
- View-specific logic like formatting dates, names, or conditional display content.
π¨ Presenters: Focus on Presentation Layer
Presenters are similar to Decorators but with a specific focus on enhancing the presentation logic. They act as a middle layer between your models and views, often combining multiple models into one cohesive interface.
Example:
# app/presenters/order_presenter.rb
class OrderPresenter
def initialize(order)
@order = order
end
def total_price
@order.items.sum(&:price) + shipping_cost
end
def shipping_cost
@order.expedited? ? 10 : 5
end
end
# Usage in Controller
@order = Order.find(params[:id])
@presenter = OrderPresenter.new(@order)
Hack:
- Use the
view_context
in your Presenter for direct access to Rails helpers, making it even more flexible:
def formatted_total_price
view_context.number_to_currency(total_price)
end
Best Use:
- When you need to abstract complex presentation logic from the view.
π οΈ Commands: Encapsulate Business Logic
The Command pattern encapsulates a business operation in a single class, making it reusable, testable, and easy to maintain. Commands are ideal for performing tasks that might otherwise clutter your models or controllers.
Example:
# app/commands/create_order_command.rb
class CreateOrderCommand
def initialize(user, cart)
@user = user
@cart = cart
end
def execute
Order.create!(user: @user, total_price: @cart.total_price)
end
end
# Usage in Controller
command = CreateOrderCommand.new(current_user, current_cart)
@order = command.execute
Hack:
- Chain commands together for workflows using a service object:
# app/services/order_service.rb
class OrderService
def initialize(user, cart)
@user = user
@cart = cart
end
def place_order
command = CreateOrderCommand.new(@user, @cart)
notify_user(command.execute)
end
private
def notify_user(order)
UserMailer.order_confirmation(order).deliver_later
end
end
Best Use:
- Encapsulating domain logic that doesnβt belong in controllers or models, like workflows or API interactions.
β‘ Quick Hacks for Efficient Usage
- Use Decorators for enhancing objects with reusable, view-specific methods.
- Leverage Presenters when combining data from multiple models into a single, clean interface for views.
- Apply Commands to separate complex operations from models and controllers.
- Naming Matters β Choose meaningful names for Decorators, Presenters, and Commands to clearly indicate their purpose.
- Testing Made Easy β Since these patterns separate concerns, theyβre easier to unit test individually. π§ͺ
π Conclusion
By integrating Decorators, Presenters, and Commands into your Ruby on Rails projects, youβll write cleaner, more maintainable code. These patterns help you stay organized, improve testability, and keep your application logic decoupled. π
What are your favorite patterns in Rails? Let us know in the comments! β¨
© Lakhveer Singh Rajput - Blogs. All Rights Reserved.