Usando o método delegate_missing_to em Ruby on Rails

Tutoriais - 01/Jul/2020 - por André Kanamura

Já falamos em artigos anteriores como delegar chamadas de métodos usando SimpleDelegator e Sobrescrevendo method_missing na implementação de design patterns como Presenter e Decorator em uma aplicação Ruby on Rails. Vamos mostrar como podemos implementar uma solução utilizando o delegate_missing_to. Sugerimos que você leia os artigos anteriores caso tenha interesse em compreender melhor os design patterns e como foram feitas as implementações do method_missing ou do SimpleDelegator. Caso contrário, pode continuar a leitura.

Em resumo, relembrando o contexto do exemplo descrito nos artigos anteriores, temos duas classes, Rental, que representa uma locação de um carro, e RentalPresenter, que vai preparar informações de Rental para visualização nas views. Para que RentalPresenter consiga executar plenamente sua função, é importante que a classe seja capaz de responder aos mesmos métodos que Rental. Com esse objetivo em mente, podemos implementar algumas estratégias como Herança ou usar SimpleDelegator, por exemplo. Outra possibilidade, como demonstramos neste artigo, seria sobrescrever method_missing na classe RentalPresenter:

class RentalPresenter
 attr_reader :rental

 def initialize(rental)
   @rental = rental
 end

  def status
    "A locação está com status: #{@rental.status}"
  end

  def method_missing(method_name, *args, &block)
    @rental.public_send(method_name, *args, &block)
  end

  def respond_to_missing?(method_name, include_private = false)
    @rental.respond_to?(method_name, include_private)
  end
end

Implementando o método method_missing em RentalPresenter conseguimos controlar o comportamento do método, repassando as chamadas de métodos que não estão implementados para @rental. Utilizando essa estratégia é necessário também implementar o método respond_to_missing?, como descrito neste artigo.

Mas esse mesmo resultado poderia ser obtido utilizando o método delegate_missing_to na classe:

class RentalPresenter
 delegate_missing_to: :@rental
 attr_reader :rental

 def initialize(rental)
   @rental = rental
 end

  def status
    "A locação está com status: #{@rental.status}"
  end
end

Você pode usar o delegate_missing_to passando a ele métodos, variáveis de instância, constantes etc. O delegate_missing_to repassa as chamadas de métodos que não estão implementados na classe para o objeto designado, neste caso @rental. Dessa forma o código fica muito mais enxuto e não é necessária nenhuma implementação secundária para tratar possíveis erros. Além disso, uma vantagem que essa estratégia apresenta em comparação com o uso do SimpleDelegator é que semanticamente o delegate_missing torna muito mais clara a intenção de sua implementação.

Existe também a opção de utilizar o delegate. Para o presente exemplo, no lugar de delegate_missing_to, bastaria incluir delegate :nome_do_metodo, to: :@rental. No entanto, seria necessário incluir cada um dos métodos faltantes e sempre que um método for adicionado a Rental a classe RentalPresenter precisaria ser atualizada.

Quando nossa intenção é apenas delegar todos os métodos faltantes para um alvo específico, o delegate_missing_to faz o trabalho necessário de forma bastante simples e direta.

Referências

Foto de perfil do autor
André Kanamura

Dev na Campus Code