Rails 3 Internals

Posted on September 12, 2010

4


O Rails 3 foi finalmente anunciado e nele uma série de mudanças arquiteturais foram feitas.
A princípio, para que programa, as mudanças podem parecer simples, penas novos comandos ou novas API’s. Mas se olharmos nos detalhes internos do framework podemos ver que as mudanças impactam diretamente na forma de usar o framework.

O Rails 3 tem uma série de melhorias, mas nesse post quero tratar especificamente de uma, que é Modularidade.
Modularidade lembra de alguma forma baixo-acoplamento, fator indispensável para uma boa arquitetura.

Active Relation

Podemos analisar a questão da modularidade de várias maneiras, aqui vamos analisar usando o ActiveRelation.
O ActiveRelation permite querys muito mais interessantes, veja essa diferença entre Rails 2 e Rails 3.

O que percebemos nessa figura é que a nova API possui métodos muito mais intuitivos e interessantes
para criar querys. Alguns detalhes importantes aqui são:

  • No Rails 2 o retorno já era um array com seus models. No Rails 3 cada método devolve um objeto chamado Relation
  • Esse objeto Relation é capaz de fazer um encadeamento de operações. Com isso, auery final só é chamada quando
    executado explicitamente algum método como all ou each.
  • No Rails 3 comportamento é Lazy Loading.

Visto isso, duas coisas podem ser analisádas:

  • Como isso é feito por dentro?
  • Como usar isso na minha app?

Internamente

Procurando internamente no fonte do Rails, encontramos o arquivo query_methods.rb. Esse é o arquivo responsável pela idéia de encadeamento:

Repare no código fonte. Independente do método chamado o Rails sempre faz uma cópia do encadeamento atual, adiciona um novo comportamento e devolve essa Relation atualizada. E quem é esse relation ?

relation é um método do ActiveRecord que verifica se o encadeamento já foi inicializado e decide por criar um novo ou devolver o mesmo.
Ainda temos na classe Relation um delegate, que roda o método to_a toda vez que o Relation for disparado. É nesse ponto que o Rails controla o hit no banco de dados. Interessante notar que o método find_by_sql ainda é utilizado, porém, com uma query
gerada pelo ARel.

Como melhorar meu código com isso?

O que não pode acontecer é apenas aceitar como funciona e usar a API. Esse encadeamneto abre novas possíbilidades de querys muito mais interessantes e otimizadas. Um ponto sempre complexo em aplicações são filtros que necessitam querys dinâmicas.

Filtros que necessitam muitos parâmetros com um número grande de combinações possíveis entre eles são complicados de fazer e manter.
Como tirar proveito do ActiveRelation pra melhorar isso ?

Se utilizarmos a mesma idéia de clonar o relation e devolve-lo de acordo com cada filtro preenchido pelo usuário, podemos montar uma implementação bem interessante com um pouco de meta-programação.

Repare que com um método filtered_relation podemos iterar sobre cada filtro possível, adicionando uma nova relation.
Cada relation é única e ensinamos como tratar com um método exclusivo.

Nesse caso utilizamos o ActiveRecord, mas hoje o Rails 3 não é opnionated. Até hoje, o Rails era considerado um
meta-framework, ou seja, um conjunto de frameworks, que juntos formavam o Rails.

No Rails 3, um componente central foi totalmente alterado para servir de fundação para o Rails. Todos os
considerados frameworks principais como ActiveRecord, ActionMailer etc deixaram de ser framewors e hoje são plugins.

O componente que organiza tudo isso é o Railtie. Todo plugin hoje é herda de Railtie. Ao inicializar o Rails,
o Railtie procura todos as classes que herdam de Railtie e começa sua inicialização. Nesse momento, cada plugin é responsável
pelo seu processo de boot, ou seja, desacoplado do Rails.

Se olhar os geradores, podemos entender como o Rails pluga os principais componentes(ActiveRecord, ActionController, etc)

Railtie + Plugins + ARel…

Se apartir do fonte do Rails criamos uma funcinalidade de filtro e se o Rails aceita fácilmente plugins hoje, por que não
juntar tudo agora ?

Podemos criar um plugin de filtros dinâmicos. Se você se interessar por ver o código ou contribuir, basta acessar o github do plugin filtered_relation

Os slides dessa apresentação estão no SlideShare

Posted in: rails