quinta-feira, 6 de setembro de 2012

Nested resources com mesmo nome e visões diferentes

Estou desenvolvendo uma aplicação em Rails e cheguei em um momente que tinha o seguinte problema: renderizar conteúdo diferente para 1 recurso aninhado de outros 2.

Vou utilizar um exemplo real para ilustrar melhor o caso. Digamos que estamos trabalhando numa aplicação parecida com o twitter e nossos 3 modelos são: usuários, postagens e tags. A partir delas eu posso ter as seguintes URLs na minha aplicação:
  • /usuario/1/postagens
  • /tags/1/postagens
Sendo necessário a seguinte configuração no meu arquivo routes.rb para obtê-las:

resources :usuarios do
  resources :postagens
end

resources :tags do
  resources :postagens
end

Sem nenhuma configuração adicional, isso irá fazer com que ambas as URL direcionem suas requisições para o mesmo controlador: PostagensController.

Para modificar este comportamento podemos utilizar namespaces. Para isso podemos criar uma pasta chamada usuario e outra chamada tag dentro do caminho /app/controllers e dentro dela colocar a classe PostagensController com o namespace correto, isto é o topo do arquivo teria que ficar da seguinte forma:
  • class Usuario::PostagensControllers < ApplicationController
  • class Tag::PostagensControllers < ApplicationController
Desta forma separamos o controlador de cada um dos nosso recursos aninhados, mas ainda precisamos instruir o Rails que ao receber uma requisição em um dos dois caminhos anteriores queremos que esta seja redirecionada para um controlador ou outro. Os guias na página do Rails tem uma parte ótima a este respeito: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing

Para o meu caso modifiquei o arquivo routes.rb para o seguinte:

resources :usuarios do
  resources :postagens, :module => "usuario"
end

resources :tags do
  resources :postagens, :module => "tag"
end


Desta forma a URL não é alterada, apenas é feito o roteamento para o controlador no namespace correto.

O maior benefício desta estratégia é poder separar as visões para cada uma das requisições, sendo que o que é geral para as duas pode ser extraída para um template, enquanto os recursos específicos não ficam poluídos com ifs desnecessários e que tornam o entendimento da aplicação mais difícil, pois acaba adicionando detalhes de domínios distintos, podendo levar a distrações durante a leitura do código.

Os arquivos da visão ficariam então no seguinte caminho:
  • app/views/usuario/postagens/index.html.erb
  • app/views/tags/postagens/index.html.erb
A seção "Grouping Controllers into Modules" do livro Agile Web Development with Rails foi de grande ajuda para descobrir como implementar esta abordagem.
Maravilha, não!?!

Nenhum comentário:

Postar um comentário