Rails Model, View, Controller et Helper: qu'est-ce qui va où?

155

Dans Ruby on Rails Development (ou MVC en général), quelle règle rapide dois-je suivre pour savoir où placer la logique.

Veuillez répondre par l'affirmative - Avec Do mettez ceci ici , plutôt que Ne mettez pas cela là .

theschmitzer
la source

Réponses:

173

MVC

Contrôleur : mettez ici le code qui a à voir avec l'élaboration de ce que veut un utilisateur et le choix de ce qu'il doit lui donner, déterminer s'il est connecté, s'il doit voir certaines données, etc. En fin de compte, le contrôleur examine les demandes et détermine quelles données (modèles) afficher et quelles vues rendre. Si vous avez des doutes sur le fait que le code doit entrer dans le contrôleur, il ne devrait probablement pas. Gardez vos contrôleurs maigres .

Vue : La vue ne doit contenir que le code minimum pour afficher vos données (modèle), elle ne doit pas faire beaucoup de traitement ou de calcul, elle doit afficher des données calculées (ou résumées) par le modèle ou générées à partir du contrôleur. Si votre vue a vraiment besoin d'effectuer un traitement qui ne peut pas être effectué par le modèle ou le contrôleur, placez le code dans un assistant. Beaucoup de code Ruby dans une vue rend le balisage des pages difficile à lire.

Modèle : Votre modèle doit être l'endroit où réside tout votre code lié à vos données (les entités qui composent votre site, par exemple les utilisateurs, la publication, les comptes, les amis, etc.). Si le code doit enregistrer, mettre à jour ou résumer des données liées à vos entités, placez-le ici. Il sera réutilisable dans vos vues et contrôleurs.

pauliephonique
la source
2
Les gens commencent à s'éloigner du gros modèle. J'aime considérer mon modèle comme une structure de données. Ensuite, j'écris un objet Ruby qui implémente le comportement, en l'initialisant avec le modèle (il traite le modèle comme ses données de la même manière que vous pourriez traiter les chaînes et les tableaux comme des données dans des objets en dehors de Rails). Voici une bonne vidéo avec un exemple de cette technique.
Joshua Cheek
@AdamDonahue Je ne suis pas sûr que quelque chose de gras puisse être considéré comme une bonne chose. Il vaut mieux avoir des tonnes de responsabilités dans les services.
fatuhoku
35

Pour ajouter à la réponse de pauliephonic:

Aide : fonctions pour faciliter la création de la vue. Par exemple, si vous parcourez toujours une liste de widgets pour afficher leur prix, placez-le dans un assistant (avec un partiel pour l'affichage réel). Ou si vous avez un morceau de RJS dont vous ne voulez pas encombrer la vue, mettez-le dans un assistant.

jcoby
la source
En fait, ne mettons-nous pas également la méthode sign_in dans Helper? Comme RoR Tutorial suggéré ici >>> ruby.railstutorial.org/book/…
Ivan Wang
14

Le modèle MVC ne concerne en réalité que l'interface utilisateur et rien d'autre. Vous ne devez pas mettre de logique métier complexe dans le contrôleur car il contrôle la vue mais pas la logique. Le contrôleur doit se préoccuper de sélectionner la vue appropriée et de déléguer des éléments plus complexes au modèle de domaine (modèle) ou à la couche métier.

La conception pilotée par le domaine a un concept de services qui est un endroit où vous collez la logique qui doit orchestrer un certain nombre de types d'objets différents, ce qui signifie généralement une logique qui n'appartient pas naturellement à une classe de modèle.

Je considère généralement la couche Service comme l'API de mes applications. Mes couches de services correspondent généralement assez étroitement aux exigences de l'application que je crée, donc la couche de service agit comme une simplification des interactions plus complexes trouvées dans les niveaux inférieurs de mon application, c'est-à-dire que vous pouvez atteindre le même objectif en contournant les couches de service. mais vous devrez tirer beaucoup plus de leviers pour que cela fonctionne.

Notez que je ne parle pas de Rails ici, je parle d'un style architectural général qui répond à votre problème particulier.

Søren Spelling Lund
la source
C'est une excellente réponse :)
Carlos Martinez
12

Des explications parfaites ici déjà, une phrase très simple en guise de conclusion et facile à retenir:

Nous avons besoin de modèles SMART, de contrôleurs THIN et de vues DUMB.

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

maddin2code
la source
7

Mettez des éléments liés à l'autorisation / au contrôle d'accès dans le contrôleur.

Les modèles concernent vos données. Validation, relations, CRUD, logique métier

Les vues consistent à afficher vos données. Afficher et obtenir des entrées uniquement.

Les contrôleurs permettent de contrôler quelles données vont de votre modèle à votre vue (et quelle vue) et de votre vue à votre modèle. Les contrôleurs peuvent également exister sans modèles.

J'aime penser au contrôleur comme à un agent de sécurité / réceptionniste qui vous dirige le client (demande) vers le comptoir approprié où vous posez une question à un caissier (voir). Le caissier (vue) va alors chercher la réponse d'un gestionnaire (modèle), que vous ne voyez jamais. Vous la demande puis retournez à l'agent de sécurité / réceptionniste (contrôleur) et attendez que vous soyez dirigé vers un autre guichetier (vue) qui vous dit la réponse que le gestionnaire (modèle) leur a donnée en réponse à la question (vue) de l'autre guichetier .

De même, si vous voulez dire quelque chose au caissier (voir), la même chose se produit en grande partie, sauf que le deuxième caissier vous dira si le gestionnaire a accepté vos informations. Il est également possible que l'agent de sécurité / réceptionniste (contrôleur) vous ait dit de faire une randonnée puisque vous n'étiez pas autorisé à communiquer cette information au gestionnaire.

Donc, pour prolonger la métaphore, dans mon monde stéréotypé et irréaliste, les scrutateurs (points de vue) sont jolis mais sans tête et croient souvent tout ce que vous leur dites, les gardes de sécurité / réceptionnistes sont peu polis mais ne sont pas très bien informés mais ils savent où les gens devraient et ne devrait pas y aller et les gestionnaires sont vraiment laids et méchants mais savent tout et peuvent dire ce qui est vrai et ce qui ne l'est pas.

srboisvert
la source
4

Une chose qui aide à séparer correctement est d'éviter l'anti-modèle "passer les variables locales du contrôleur à la vue". Au lieu de cela:

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

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

end

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

Essayez de le déplacer vers un getter disponible comme méthode d'assistance:

# 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 %>
...

Cela rend plus facile de modifier ce qui est mis dans "@foo" et comment il est utilisé. Cela augmente la séparation entre le contrôleur et la vue sans les rendre plus compliqués.

James A. Rosen
la source
euhmmm ... Yuk. Pouvez-vous s'il vous plaît ajouter quelques bonnes raisons / scénarios pour lesquels vous feriez cela. Cela brise KISS et YAGNI et ça sent très mauvais (juste pour ajouter un autre cliché)
Sixty4Bit
2
1) Rails fait beaucoup de magie pour copier les variables d'instance du contrôleur dans votre instance de vue. 2) L'implémentation suggérée ne charge également foo que si elle est accédée, ce qui peut économiser du travail une partie du temps. La réponse importante est en fait 1), cependant.
webmat
11
Soupir C'est terrible. Le partage de variables d'instance Rails est une fonctionnalité et non un anti-pattern. C'est un sucre syntaxique omniprésent, à faible charge mentale, qui pose rarement, voire jamais, des problèmes dans le monde réel. Si vous ne l'aimez pas, très bien, mais coder autour de lui avec une structure baroque non standard rend les choses infiniment pires. Dans ce cas, vous faites effectivement de foo une variable globale (par contrôleur de toute façon). Tenter de corriger un abus perçu de la portée variable en augmentant considérablement la portée est extrêmement ironique.
gtd
1
Je ne l'achète pas, dasil003. La portée de fooet de @foosont les mêmes - ils sont tous deux étendus à la paire <ControllerClass, request>. De plus, en utilisant la version getter, je peux changer la façon dont cet Fooobjet est trouvé / stocké / mis en cache sans changer la façon dont la vue y accède.
James A. Rosen
1
Je pense que vous voulez dire l'anti-pattern "passer des variables d'instance". Une variable d'instance perdra son état pour tout le rendu, même dans les partiels profondément imbriqués. Votre solution perd également son état, mais elle est légèrement meilleure qu'une variable d'instance car elle ne permet pas la réaffectation. Passer un local est en fait le meilleur car c'est comme appeler une méthode; le local ne peut pas être vu par les partiels. Voyez cette réponse .
Kelvin
2

Eh bien, cela dépend en quelque sorte de ce à quoi la logique doit faire face ...

Souvent, il est logique de pousser plus de choses dans vos modèles, laissant les contrôleurs petits. Cela garantit que cette logique peut facilement être utilisée depuis n'importe quel endroit où vous avez besoin d'accéder aux données que votre modèle représente. Les vues ne doivent presque contenir aucune logique. Donc vraiment, en général, vous devriez vous efforcer de faire en sorte que vous ne vous répétiez pas.

En outre, un petit bout de google révèle quelques exemples plus concrets de ce qui va où.

Modèle: exigences de validation, relations de données, créer des méthodes, mettre à jour des méthodes, détruire des méthodes, rechercher des méthodes (notez que vous devriez avoir non seulement les versions génériques de ces méthodes, mais s'il y a quelque chose que vous faites beaucoup, comme trouver des personnes avec hair par nom de famille, alors vous devriez extraire cette logique pour que tout ce que vous ayez à faire soit d'appeler le find_redH_by_name ("smith") ou quelque chose comme ça)

Vue: Tout cela devrait concerner le formatage des données, pas le traitement des données.

Contrôleur: C'est là que va le traitement des données. Depuis Internet: "Le but du responsable du traitement est de répondre à l'action demandée par l'utilisateur, de prendre tous les paramètres définis par l'utilisateur, de traiter les données, d'interagir avec le modèle, puis de transmettre les données demandées, sous leur forme finale, au vue."

J'espère que cela pourra aider.

Paul Wicks
la source
0

En termes simples, en général, les modèles auront tous les codes liés aux tables, leurs relations simples ou complexes (pensez-les comme des requêtes sql impliquant plusieurs tables), la manipulation des données / variables pour arriver à un résultat en utilisant la logique métier .

Les contrôleurs auront des codes / pointeurs vers les modèles pertinents pour le travail demandé.

Views acceptera l'entrée / l'interaction de l'utilisateur et affichera la réponse résultante.

Tout écart majeur par rapport à ceux-ci exercera une pression indésirable sur cette pièce et les performances globales de l'application peuvent être affectées.

Anutosh
la source
-1

Test, test ... Mettez autant de logique que possible dans le modèle et vous pourrez alors le tester correctement. Les tests unitaires testent les données et la façon dont elles sont formées en testant le modèle, et les tests fonctionnels testent la façon dont elles sont acheminées ou contrôlées en testant les contrôleurs, il s'ensuit donc que vous ne pouvez pas tester l'intégrité des données à moins qu'elles ne soient en le modèle.

j


la source