Ruby on Rails uma forma mais inteligente de organizar controladores e helpers

Estou trabalhando numa nova aplicação em Rails, ela é dividida em área administrativa e uma área vísivel a todos os visitantes da aplicação.

Inicialmente eu comecei com os controladores admin_controller.erb, home_controller.erb e o controlador padrão application_controller.erb, que é herdado pelos dois primeiros controladores.

application_controller.erb

1
2
3
4
5
6
7
8
9
10
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
 
class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
 
  # Scrub sensitive parameters from your log
  # filter_parameter_logging :password
end

admin_controller.erb

1
2
3
4
5
6
class AdminController < ApplicationController
 
  def index
  end
 
end

home_controller.erb

1
2
3
4
5
6
class HomeController < ApplicationController
 
  def index
  end
 
end

Mas eu quero deixar a minha aplicação mais simples e inteligente, a minha área administrativa vai ser grande, bem como o meu frontend.

Vão existir uma série de filtros e helpers que vão ser usados em comum por todos os diversos controladores da área administrativa e do frontend, do jeito que está hoje eu teria que colocar muito código no application_controller.erb, bem como no helper padrão application_helper.erb.

Desta forma eu decidi criar dois novos controladores backend_controller.erb e frontend_controller.erb, a minha ideia é fazer todos os controladores da área administrativa herdarem o backend_controller.erb, e todos os controladores do meu frontend herdarem o controlador frontend_controller.erb. Por sua vez os controladores backend_controller.erb e frontend_controller.erb herdarão o application_controller.erb, o que garante que a minha aplicação vai continuar funcionando corretamente.

Fazendo isso eu ganho um grau maior de componentização dos controladores, quando eu adicionar um filtro, método ou helper no backend_controller.erb ou frontend_controller.erb todos os controladores filhos deles já terão essa funcionalidade disponível.

Seguindo essa ideia eu fiz algumas alterações para implementar esse recurso:

Criei dois novos controladores:

backend_controller.erb

1
2
3
4
5
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class BackendController < ApplicationController
end

frontend_controller.erb

1
2
3
4
5
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class FrontendController < ApplicationController
end

Alterei os controladores abaixo, para herdarem os controladores criados acimas:

admin_controller.erb

1
2
3
4
5
6
class AdminController < BackendController
 
  def index
  end
 
end

home_controller.erb

1
2
3
4
5
6
class HomeController < FrontendController
 
  def index
  end
 
end

Fazendo isso eu consigo ganhar uma componentização muito grande, se eu adicionar alguma coisa no controlador application_controller.erb, ele está disponível tanto no admin como no frontend.

Adicionando algo no frontend_controller.erb estará disponível em todo o frontend e adicionando algo no backend_controller.erb estará disponível em todo o admin.

É possível melhorar mais ainda, vamos criar dois novos helpers:

backend_helper.rb

1
2
module BackendHelper
end

frontend_helper.rb

1
2
module FrontendHelper
end

Vou colocar esses helpers para serem carregados em todos os controladores que herdam backend_controller.rb e frontend_controller.erb:

backend_controller.rb

1
2
3
4
5
6
7
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class BackendController < ApplicationController
  layout "admin"
  helper :backend
end

Acima eu aproveitei e adicionei o layout “admin.html.erb”, que será usado por todos as views da área administrativa.

frontend_controller.rb

1
2
3
4
5
6
# Filtros adicionados nesse controlador serão aplicados em todos os controladores filhos
# De igual modo, todos os métodos adicionados estarão disponíveis para todos os controladores filhos
 
class FrontendController < ApplicationController
  helper :frontend
end

Agora no application_controller.erb, comente a linha helper :all, para não carregar todos os helpers, só os que você precisa.

1
2
3
4
5
6
7
8
9
10
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
 
class ApplicationController < ActionController::Base
  # helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
 
  # Scrub sensitive parameters from your log
  # filter_parameter_logging :password
end

Pronto! ;-)

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

  • Share/Bookmark

6 Comments

  1. Wilker

    acho que outra ideia legal seria usar o Rails Engines para criar o backend como uma aplicação separada, e o front-end iria se aproveitar apenas dos modelos para exibição das coisas

    esse esquema é legal pois assim fica mais fácil para aproveitar o backend em futuras aplicações ;)

  2. patrickespake

    Legal, não conheço Rails Engines. Vou estudar e ver como funciona.

    Valeu pela dica.
    Abraço.

  3. Legal Patrick,

    gostei bastante desse modelo de separação, muito interessante…

    Também a idéia do Wilker utilizando os Engines deve facilitar a modularização..

  4. patrickespake

    Pelo Post do Akita: http://www.akitaonrails.com/2009/03/14/rails-2-3-amanha

    Rails Engines não parece ser uma boa agora, talvez no Rails 3.

    “No atual estado, esse suporte ainda é incompleto. Por exemplo, o Rails 2.3 ainda não suportará Engines com migrations, ainda não suporta bem assets públicos (imagens, javascript, etc dentro do plugin). Mas de fato este é um passo na direção correta. Eu espero que na próxima versão isso se complete.”

  5. Wilker

    Mas veja também o screencast do Ryan Bates: http://railscasts.com/episodes/149-rails-engines

    ele além de mostrar como funciona, ainda mostra como “suprir” esses problemas de arquivos de public/migrations utilizando sincronizacao de diretorio ;)

  6. patrickespake

    Cara muito massa Rails Engines, vai cair muito bem em diversas coisas que eu quero fazer.

    Valeu!
    Obrigado.



Add Your Comment