Pattern Service Objects em Ruby
Tags: ruby, rails, patter, programming
Published: 2023-02-24 00:33:47

O padrão de design Service Objects é uma técnica útil e popular em Ruby on Rails para gerenciar a lógica de negócios complexa em seus aplicativos. O objetivo deste padrão é separar a lógica de negócios do controlador ou modelo e colocá-la em classes independentes chamadas de Service Objects. Esses objetos de serviço são responsáveis por executar uma tarefa específica ou um conjunto de tarefas relacionadas, tornando o código mais modular, legível e fácil de testar.

Vamos ver como implementar o padrão Service Objects em Ruby on Rails com um exemplo prático.

Suponha que temos um aplicativo que permite aos usuários reservar quartos de hotel. Quando um usuário faz uma reserva, precisamos verificar se o quarto está disponível e, em seguida, atualizar a disponibilidade do quarto e criar um registro de reserva no banco de dados.

Em vez de colocar toda a lógica de reserva em um controlador ou modelo, podemos criar um Service Object chamado ReservationService para gerenciar o processo de reserva. Aqui está um exemplo de implementação:

```ruby
class ReservationService
  def initialize(room, user, start_date, end_date)
    @room = room
    @user = user
    @start_date = start_date
    @end_date = end_date
  end

  def call
    raise ArgumentError, 'Room is not available for these dates' unless room_available?

    create_reservation
  end

  private

  attr_reader :room, :user, :start_date, :end_date

  def room_available?
    # Check if room is available for the given dates
    !Reservation.exists?(room: room, end_date >= start_date, start_date <= end_date)
  end

  def create_reservation
    # Create reservation record in the database
    Reservation.create(room: room, user: user, start_date: start_date, end_date: end_date)
  end
end
```

Neste exemplo, o construtor do ReservationService recebe o quarto, o usuário e as datas de início e término da reserva. O método call é o ponto de entrada para o Service Object e é responsável por executar as tarefas de reserva.

O método room_available? verifica se o quarto está disponível para as datas da reserva. Ele usa a consulta ActiveRecord exists? para verificar se há alguma reserva que esteja ocorrendo durante as datas solicitadas.

O método create_reservation é responsável por criar o registro de reserva no banco de dados usando o modelo Reservation.

Agora, podemos chamar o ReservationService no controlador para processar as solicitações de reserva:

```ruby
class ReservationsController < ApplicationController
  def create
    @room = Room.find(params[:room_id])
    @reservation = ReservationService.new(@room, current_user, params[:start_date], params[:end_date]).call

    if @reservation.persisted?
      flash[:notice] = 'Reservation successfully created'
      redirect_to @reservation
    else
      flash.now[:alert] = 'Error creating reservation'
      render 'rooms/show'
    end
  end
end
```

Neste exemplo, o controlador chama o ReservationService com o quarto, o usuário atual e as datas de início e término da reserva. Se a reserva for criada com sucesso, o usuário é redirecionado para a página de detalhes da reserva. Caso contrário, uma mensagem de erro é exibida.

Conclusão:

O padrão de design Service Objects é uma técnica poderosa para manter a lógica de negócios do seu aplicativo separada do controlador ou modelo. Isso ajuda a tornar seu código mais modular, legível e fácil de testar. Além disso, ele oferece uma solução escalável e flexível para gerenciar a lógica de negócios complexa.

No exemplo acima, criamos um Service Object chamado ReservationService para gerenciar o processo de reserva de quartos de hotel. Ao separar a lógica de negócios em um objeto separado, podemos testá-lo de forma isolada e alterá-lo sem afetar o resto do código. Isso torna o processo de desenvolvimento mais eficiente e mais fácil de manter.

Embora este exemplo seja específico para reservas de quartos de hotel, você pode usar o padrão Service Objects para gerenciar qualquer tipo de lógica de negócios em seu aplicativo. Espero que este exemplo prático ajude você a entender melhor como usar o padrão de design Service Objects em seus projetos Ruby on Rails.