Modelo, Visão, Controlador e Auxiliar do Rails: o que vai aonde?

155

No Ruby on Rails Development (ou MVC em geral), que regra rápida devo seguir sobre onde colocar a lógica.

Por favor, responda afirmativamente - Com Do coloque isso aqui , em vez de Não coloque isso lá .

theschmitzer
fonte

Respostas:

173

MVC

Controlador : coloque aqui o código que tem a ver com descobrir o que o usuário deseja e decidir o que dar a ele, determinar se está logado, se deve ver determinados dados etc. No final, o controlador analisa solicitações e calcula quais dados (modelos) mostrar e quais visualizações renderizar. Se você está em dúvida sobre se o código deve ir no controlador, provavelmente não deveria. Mantenha seus controladores magros .

Visualização : A visualização deve conter apenas o código mínimo para exibir seus dados (Modelo), não deve processar muito ou calcular, deve exibir dados calculados (ou resumidos) pelo Modelo ou gerados a partir do Controlador. Se o seu View realmente precisar executar um processamento que não pode ser feito pelo Modelo ou Controlador, coloque o código em um Auxiliar. Muitos códigos Ruby em um View dificultam a leitura da marcação das páginas.

Modelo : seu modelo deve estar onde vive todo o seu código relacionado aos seus dados (as entidades que compõem seu site, por exemplo, Usuários, Post, Contas, Amigos etc.). Se o código precisar salvar, atualizar ou resumir dados relacionados às suas entidades, coloque-o aqui. Será reutilizável nas suas Visualizações e Controladores.

pauliephonic
fonte
2
As pessoas estão começando a se afastar do modelo gordo. Eu gosto de pensar no meu modelo como uma estrutura de dados. Depois, escrevo um objeto Ruby que implementa o comportamento, inicializando-o com o modelo (ele trata o modelo como dados, da mesma maneira que você pode tratar strings e matrizes como dados em objetos fora do Rails). Aqui está um bom vídeo com um exemplo dessa técnica.
Joshua Cheek
@AdamDonahue Não tenho certeza se algo gordo pode ser visto como uma coisa boa. Toneladas de responsabilidades pertencem melhor aos serviços.
Fatuhoku 08/12/19
35

Para adicionar à resposta de pauliephonic:

Auxiliar : funções para facilitar a criação da visualização. Por exemplo, se você estiver sempre repetindo uma lista de widgets para exibir o preço deles, coloque-o em um auxiliar (junto com um parcial para a exibição real). Ou, se você tem um pedaço de RJS que não deseja encher de vista, coloque-o em um ajudante.

jcoby
fonte
Na verdade, também não colocamos o método sign_in no Helper? Como RoR Tutorial sugerida aqui >>> ruby.railstutorial.org/book/...
Ivan Wang
14

O padrão MVC está realmente preocupado apenas com a interface do usuário e nada mais. Você não deve colocar nenhuma lógica comercial complexa no controlador, pois controla a exibição, mas não a lógica. O Controller deve se preocupar em selecionar a exibição apropriada e delegar itens mais complexos ao modelo de domínio (Modelo) ou à camada de negócios.

O Design Orientado a Domínio tem um conceito de Serviços, que é um local onde você adere à lógica, que precisa orquestrar vários tipos de objetos, o que geralmente significa lógica que naturalmente não pertence a uma classe Model.

Geralmente penso na camada de serviço como a API dos meus aplicativos. As camadas Meus serviços geralmente mapeiam de perto os requisitos do aplicativo que estou criando, portanto, a camada Serviço atua como uma simplificação das interações mais complexas encontradas nos níveis mais baixos do meu aplicativo, ou seja, você pode atingir o mesmo objetivo ignorando as camadas Serviço mas você teria que puxar muito mais alavancas para fazê-lo funcionar.

Observe que não estou falando sobre Rails aqui, estou falando sobre um estilo arquitetural geral que aborda seu problema específico.

Søren Spelling Lund
fonte
Esta é uma grande resposta :)
Carlos Martinez
12

Explicações perfeitas aqui já, uma frase muito simples como conclusão e fácil de lembrar:

Precisamos de modelos SMART, controladores THIN e vistas DUMB.

http://c2.com/cgi/wiki?ModelViewController

maddin2code
fonte
7

Coloque coisas relacionadas à autorização / controle de acesso no controlador.

Os modelos são todos sobre seus dados. Validação, Relacionamentos, CRUD, Lógica de Negócios

As visualizações são sobre mostrar seus dados. Exibir e obter apenas entrada.

Os controladores tratam de controlar quais dados vão do seu modelo para a sua visualização (e qual visualização) e da sua visualização para o seu modelo. Os controladores também podem existir sem modelos.

Gosto de pensar no controlador como um segurança / recepcionista que direciona o cliente (solicitação) para o balcão apropriado, onde você faz uma pergunta ao caixa (visualiza). O caixa (visão) vai e recebe a resposta de um gerente (modelo), que você nunca vê. Você solicita e volta ao guarda de segurança / recepcionista (controlador) e aguarda até ser direcionado a procurar outro caixa (visão) que lhe diz a resposta que o gerente (modelo) lhes disse em resposta à pergunta (visão) do outro caixa .

Da mesma forma, se você quiser dizer ao caixa (ver) algo, em grande parte acontece a mesma coisa, exceto que o segundo caixa informará se o gerente aceitou suas informações. Também é possível que o guarda de segurança / recepcionista (controlador) tenha solicitado que você fizesse uma caminhada, pois você não estava autorizado a informar essas informações ao gerente.

Portanto, para estender a metáfora, em meu mundo estereotipado e irrealista, os caixas (pontos de vista) são bonitos, mas têm a cabeça vazia e geralmente acreditam em qualquer coisa que você lhes diga, seguranças / recepcionistas são minimamente educados, mas pouco informados, mas sabem onde as pessoas devem e os gerentes são realmente feios e maus, mas sabem tudo e sabem o que é verdade e o que não é.

srboisvert
fonte
4

Uma coisa que ajuda a separar adequadamente é evitar o antipadrão "passar variáveis ​​locais do controlador para exibir". Em vez disso:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  def show
    @foo = Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= @foo.bar %>
...

Tente movê-lo para um getter disponível como método auxiliar:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  helper_method :foo

  def show
  end

  protected

  def foo
    @foo ||= Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...

Isso facilita a modificação do que é colocado no "@foo" e como ele é usado. Aumenta a separação entre o controlador e a visualização sem torná-los mais complicados.

James A. Rosen
fonte
uhmmm ... Yuk. Você pode adicionar algumas boas razões / cenários para quando você faria isso. Isso quebra beijo e YAGNI e é muito malcheiroso (apenas para atirar em mais um clichê)
Sixty4Bit
2
1) O Rails faz muita mágica para copiar as variáveis ​​de instância do controlador para sua instância de exibição. 2) A implementação sugerida também só carrega foo se for acessada, o que pode poupar algum trabalho algumas vezes. A resposta importante é realmente 1), no entanto.
Webmat
11
Suspiro Isso é terrível. O compartilhamento de variáveis ​​da instância do Rails é um recurso, não um antipadrão. É um açúcar sintático onipresente e de baixa sobrecarga mental que raramente causa problemas no mundo real. Se você não gosta, tudo bem, mas codificá-lo com uma estrutura barroca e não-padrão torna as coisas infinitamente piores. Nesse caso, você está efetivamente transformando em uma variável global (por controlador de qualquer maneira). Tentar corrigir um abuso percebido de escopo de variáveis ​​aumentando drasticamente o escopo é extremamente irônico.
Gtd
1
Não estou comprando, dasil003. O escopo de fooe de @fooé o mesmo - ambos têm o escopo definido para o par <ControllerClass, request>. Além disso, usando a versão getter, posso alterar como esse Fooobjeto é encontrado / armazenado / armazenado em cache sem alterar a maneira como a exibição o acessa.
James A. Rosen
1
Eu acho que você quer dizer "passar variáveis ​​de instância" anti-padrão. Uma instância var vazará o estado para toda a renderização, mesmo em parciais profundamente aninhadas. Sua solução também vaza de estado, mas é um pouco melhor que uma instância var, porque não permite a reatribuição. Passar um local é realmente o melhor, porque é como chamar um método; o local não pode ser visto por parciais. Veja esta resposta .
Kelvin
2

Bem, depende do que a lógica tem que lidar ...

Freqüentemente, faz sentido inserir mais itens em seus modelos, deixando os controladores pequenos. Isso garante que essa lógica possa ser usada facilmente de qualquer lugar em que você precise acessar os dados que seu modelo representa. As visualizações não devem conter quase nenhuma lógica. Então, realmente, em geral, você deve se esforçar para fazer isso para que você não se repita.

Além disso, um pequeno pedaço do google revela alguns exemplos mais concretos do que vai aonde.

Modelo: requisitos de validação, relacionamentos de dados, criar métodos, atualizar métodos, destruir métodos, encontrar métodos (observe que você deve ter não apenas as versões genéricas desses métodos, mas se houver algo que esteja fazendo muito, como encontrar pessoas com vermelho) hair pelo sobrenome, então você deve extrair essa lógica para que tudo o que você precise fazer é chamar o find_redH_by_name ("smith") ou algo parecido)

Ver: isso deve ser tudo sobre formatação de dados, não o processamento de dados.

Controlador: É aqui que o processamento de dados vai. Na internet: "O objetivo do controlador é responder à ação solicitada pelo usuário, pegar todos os parâmetros que o usuário definiu, processar os dados, interagir com o modelo e passar os dados solicitados, na forma final, para o Visão."

Espero que ajude.

Paul Wicks
fonte
0

Em termos simples, geralmente, os Modelos terão todos os códigos relacionados às tabelas, seus relacionamentos simples ou complexos (pense em consultas sql envolvendo várias tabelas), manipulação dos dados / variáveis ​​para chegar a um resultado usando a lógica de negócios .

Os controladores terão código / ponteiros para os modelos relevantes para o trabalho solicitado.

As visualizações aceitarão a entrada / interação do usuário e exibirão a resposta resultante.

Qualquer desvio importante desses fatores causará tensão indesejada nessa parte e o desempenho geral do aplicativo poderá ser afetado.

Anutosh
fonte
-1

Testando, testando ... Coloque o máximo de lógica possível no modelo e poderá testá-lo corretamente. Os testes de unidade testam os dados e a forma como eles são formados testando o modelo, e os testes funcionais testam a maneira como eles são roteados ou controlados testando os controladores; portanto, você não pode testar a integridade dos dados, a menos que estejam em o modelo.

j


fonte