DEV Community

Rodrigo Barreto
Rodrigo Barreto

Posted on

Evoluindo nosso Projeto Rails: Integrando o Padrão Factory para Maior Flexibilidade e Organização

No meu post anterior Os benefícios de usar Form Objects em seus projetos, discutimos os benefícios significativos de utilizar Form Objects em projetos Ruby on Rails, usando um sistema de reserva de eventos como exemplo.

O padrão Factory é benéfico para situações onde você tem várias subclasses ou tipos de objetos similares e quer abstrair a lógica de criação desses objetos. Ele é útil para manter o código organizado e fácil de manter, especialmente quando há necessidade de adicionar novos tipos de objetos no futuro. O Factory permite centralizar a criação de objetos, facilitando mudanças e expandindo a aplicação sem grandes alterações na base de código existente. É ideal para projetos que requerem flexibilidade e escalabilidade na gestão de diferentes instâncias de objetos.

Continuando nossa jornada para aprimorar ainda mais essa aplicação, neste post, exploraremos como a integração do padrão Factory pode trazer uma nova dimensão de flexibilidade e eficiência. Ao expandir nosso sistema para incluir um novo tipo de evento - o concert - veremos como o Factory nos permite gerenciar a crescente complexidade de forma mais elegante, mantendo nosso código enxuto e facilmente expansível. Vamos mergulhar nos detalhes de como essa abordagem pode ser um divisor de águas na otimização e escalabilidade de nossos projetos Rails.

Imagine a situação em que o nosso gerente de produto nos pede para adicionar um novo tipo de evento, o concerto (concert), ao nosso sistema nesta semana. Além disso, ele nos alerta que em breve surgirão mais tipos de eventos, como casamento (wedding) e outros.

Portanto, é crucial que preparemos a estrutura de eventos de forma que possa ser facilmente escalada. Isso envolve criar um sistema onde a adição de novos tipos de eventos possa ser feita de maneira simples e eficiente, garantindo a flexibilidade e a adaptabilidade do nosso projeto às futuras demandas e necessidades.

Agora, vamos avançar na construção do nosso sistema, criando um novo objeto de formulário: EventConcertForm. Este formulário será específico para lidar com as características e validações únicas de eventos do tipo "concert". Implementar esse formulário é um passo importante para expandir a capacidade da nossa aplicação de gerenciar diferentes tipos de eventos de forma eficiente e organizada.

No EventConcertForm, aplicaremos uma regra específica: é necessário que o evento tenha um número de participantes maior que 100. Essa validação simples assegura que os eventos do tipo "concert" sejam apropriados para um grande público, o que é uma característica comum deste tipo de evento. A implementação dessa regra no formulário ajudará a manter a consistência e a relevância dos dados de eventos do tipo "concert" na nossa aplicação.

# frozen_string_literal: true

module Events
  class EventConcertForm < Events::EventFormBase
    validates :number_of_people, numericality: { greater_than: 100 }
  end
end

Enter fullscreen mode Exit fullscreen mode

No nosso projeto Rails, fizemos uma atualização no EventFormBase.rb, introduzindo um novo método create. Esse método valida e cria um evento diretamente dentro do formulário, exemplificando uma abordagem mais modular e organizada no manejo de dados. Essa mudança reflete nosso compromisso com a eficiência e a clareza no desenvolvimento da aplicação.

# frozen_string_literal: true

module Events
  class EventFormBase
    include ActiveModel::Model

    attr_accessor :title, :description, :event_type, :number_of_people, :special_requests

    validates :title, :event_type, :number_of_people, presence: true

    def attributes
      {
        title:,
        description:,
        event_type:,
        number_of_people:,
        special_requests:
      }
    end

    def create
      return false unless valid?

      event = Event.new(attributes)
      event.save!
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Na estrutura criada a BaseFactory serve como um molde para as Factories(Fábricas), definindo um método de classe callque instancia e chama um método call no objeto criado. Este método call deve ser implementado nas subclasses concretas. Já a EventFactory é uma implementação específica da BaseFactory, onde definimos um método initialize para configurar a ação e os parâmetros e um método call que seleciona e instancia o formulário de evento apropriado com base na ação fornecida. Isso facilita a criação flexível e dinâmica de diferentes tipos de formulários de eventos, como "birthday", "business" e "concert", com base nos parâmetros recebidos.


class BaseFactory
  class << self
    def call(...)
      new(...).call
    end
  end

  def call
    raise NotImplementedError, "'#{__method__}' should be implemented in concrete class"
  end
end
Enter fullscreen mode Exit fullscreen mode

# frozen_string_literal: true
    class EventFactory < BaseFactory
      class InvalidEventTypeError < StandardError; end
      attr_accessor :action, :params

      def initialize(action:, params:)
        @action = action
        @params = params
      end

      def call
        action_service = events[action]
        raise InvalidEventTypeError unless action_service

        action_service.new(**params)
      end

      private

      def events
        {
          "birthday": Events::EventBirthdayForm,
          "business": Events::EventBusinessForm,
          "concert": Events::EventConcertForm,
        }
      end
end
Enter fullscreen mode Exit fullscreen mode

Com a introdução da EventFactory, o EventsController será refinado para uma abordagem mais limpa e eficiente. Essa mudança não só melhora a clareza do código, mas também facilita a inclusão de novos tipos de eventos.

# frozen_string_literal: true

module Api
  module V1
    class EventsController < ApplicationController

      def create
        form = EventFactory.call(action: event_params[:event_type].to_sym, params: event_params)

        if form.create
          render json: form, status: :created
        else
          render json: form.errors, status: :unprocessable_entity
        end
      rescue EventFactory::InvalidEventTypeError => e
        render json: { error: e.message }, status: :bad_request
      end

      private
      def event_params
        params.require(:event).permit(:title, :description, :event_type, :number_of_people, :special_requests)
      end
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

O EventsController agora está mais enxuto e organizado, com a eliminação dos métodos create_event e build_event_form. A introdução da EventFactory permite que as responsabilidades de criação de formulários de eventos sejam separadas de forma mais eficiente, substituindo o antigo build_event_form. Essa mudança demonstra um uso eficaz do padrão Factory, realçando a clareza e a modularidade do código em nosso projeto Rails.

Se você estiver interessado em testar o código, pode fazer isso clonando o projeto na branch factory_pattern do repositório no GitHub. Acesse factory_pattern para ir diretamente à branch específica e explorar como o padrão Factory foi implementado no sistema de reserva de eventos.

Top comments (1)

Collapse
 
lorennav profile image
Lorenna Vieira

Muito interessante!