Rails Model, View, Controller und Helper: Was geht wohin?

155

Welche schnelle Regel sollte ich in Ruby on Rails Development (oder MVC im Allgemeinen) befolgen, wo Logik platziert werden soll?

Bitte bejahen Sie dies - Mit Do setzen Sie dies hier , anstatt das nicht dort zu setzen .

theschmitzer
quelle

Antworten:

173

MVC

Controller : Geben Sie hier Code ein, der damit zu tun hat, was ein Benutzer möchte, zu entscheiden, was er ihm geben soll, ob er angemeldet ist, ob er bestimmte Daten sehen soll usw. Am Ende prüft der Controller die Anforderungen und ermittelt, welche Daten (Modelle) angezeigt und welche Ansichten gerendert werden sollen. Wenn Sie sich nicht sicher sind, ob Code in den Controller gelangen soll, sollte dies wahrscheinlich nicht der Fall sein. Halten Sie Ihre Controller dünn .

Ansicht : Die Ansicht sollte nur den Mindestcode für die Anzeige Ihrer Daten (Modell) enthalten, sie sollte nicht viel verarbeiten oder berechnen, sie sollte Daten anzeigen, die vom Modell berechnet (oder zusammengefasst) oder vom Controller generiert wurden. Wenn Ihre Ansicht wirklich eine Verarbeitung ausführen muss, die vom Modell oder Controller nicht ausgeführt werden kann, geben Sie den Code in einen Helper ein. Viel Ruby-Code in einer Ansicht macht das Seiten-Markup schwer lesbar.

Modell : In Ihrem Modell sollte sich der gesamte Code befinden, der sich auf Ihre Daten bezieht (die Entitäten, aus denen Ihre Website besteht, z. B. Benutzer, Post, Konten, Freunde usw.). Wenn Code Daten zu Ihren Entitäten speichern, aktualisieren oder zusammenfassen muss, geben Sie ihn hier ein. Es kann in Ihren Ansichten und Controllern wiederverwendet werden.

pauliephonic
quelle
2
Die Leute beginnen sich vom fetten Modell zu entfernen. Ich stelle mir mein Modell gerne als Datenstruktur vor. Dann schreibe ich ein Ruby-Objekt, das das Verhalten implementiert und mit dem Modell initialisiert (es behandelt das Modell als Daten genauso, wie Sie Zeichenfolgen und Arrays als Daten in Objekten außerhalb von Rails behandeln könnten). Hier ist ein gutes Video mit einem Beispiel für diese Technik.
Joshua Cheek
@AdamDonahue Ich bin nicht sicher, ob Fett etwas als eine gute Sache angesehen werden kann. Tonnen von Verantwortlichkeiten sind besser dran, zu Dienstleistungen zu gehören.
Fatuhoku
35

Um die Antwort von pauliephonic zu ergänzen:

Helfer : Funktionen zur Erleichterung der Erstellung der Ansicht. Wenn Sie beispielsweise immer eine Liste von Widgets durchlaufen, um deren Preis anzuzeigen, fügen Sie sie in einen Helfer ein (zusammen mit einem Teil für die tatsächliche Anzeige). Oder wenn Sie ein Stück RJS haben, das die Ansicht nicht überladen soll, legen Sie es in einen Helfer.

jcoby
quelle
Setzen wir die Methode sign_in nicht auch in Helper ein? Wie RoR Tutorial hier vorgeschlagen >>> ruby.railstutorial.org/book/…
Ivan Wang
14

Das MVC-Muster befasst sich wirklich nur mit der Benutzeroberfläche und sonst nichts. Sie sollten keine komplexe Geschäftslogik in den Controller einfügen, da dieser die Ansicht, aber nicht die Logik steuert. Der Controller sollte sich mit der Auswahl der richtigen Ansicht befassen und komplexere Inhalte an das Domänenmodell (Modell) oder die Geschäftsschicht delegieren.

Domain Driven Design hat ein Service-Konzept, bei dem Sie die Logik festlegen, um eine Reihe verschiedener Objekttypen zu orchestrieren. Dies bedeutet im Allgemeinen Logik, die natürlich nicht zu einer Modellklasse gehört.

Ich stelle mir die Service-Schicht im Allgemeinen als API meiner Anwendungen vor. Meine Services-Layer entsprechen normalerweise ziemlich genau den Anforderungen der Anwendung, die ich erstelle. Daher dient der Service-Layer als Vereinfachung der komplexeren Interaktionen in den unteren Ebenen meiner App, dh Sie können das gleiche Ziel unter Umgehung der Service-Layer erreichen Aber Sie müssten viel mehr Hebel ziehen, damit es funktioniert.

Beachten Sie, dass ich hier nicht über Rails spreche. Ich spreche von einem allgemeinen Architekturstil, der Ihr spezielles Problem anspricht.

Søren Rechtschreibung Lund
quelle
Dies ist eine großartige Antwort :)
Carlos Martinez
12

Perfekte Erklärungen hier schon, ein sehr einfacher Satz als Abschluss und leicht zu merken:

Wir benötigen SMART-Modelle, THIN-Controller und DUMB-Ansichten.

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

maddin2code
quelle
7

Legen Sie Dinge in Bezug auf Autorisierung / Zugriffskontrolle in den Controller.

Bei Modellen dreht sich alles um Ihre Daten. Validierung, Beziehungen, CRUD, Geschäftslogik

In Ansichten geht es darum, Ihre Daten anzuzeigen. Nur anzeigen und Eingaben abrufen.

Bei Controllern geht es darum zu steuern, welche Daten von Ihrem Modell zu Ihrer Ansicht (und welche Ansicht) und von Ihrer Ansicht zu Ihrem Modell gelangen. Controller können auch ohne Modelle existieren.

Ich stelle mir den Controller gerne als Sicherheitsbeamten / Empfangsmitarbeiter vor, der Sie als Kunden (Anfrage) an den entsprechenden Schalter weiterleitet, an dem Sie einem Kassierer (Ansicht) eine Frage stellen. Der Kassierer (Ansicht) geht dann und erhält die Antwort von einem Manager (Modell), den Sie nie sehen. Sie erhalten dann die Anfrage zurück zum Sicherheitsbeamten / Empfangsmitarbeiter (Controller) und warten, bis Sie angewiesen werden, zu einem anderen Kassierer (Ansicht) zu gehen, der Ihnen die Antwort gibt, die der Manager (Modell) ihnen als Antwort auf die Frage des anderen Kassierers (Ansicht) gegeben hat .

Wenn Sie dem Kassierer (Ansicht) etwas mitteilen möchten, geschieht weitgehend dasselbe, außer dass der zweite Kassierer Ihnen mitteilt, ob der Manager Ihre Informationen akzeptiert hat. Es ist auch möglich, dass der Sicherheitsbeamte / Empfangsmitarbeiter (Controller) Sie aufgefordert hat, eine Wanderung zu unternehmen, da Sie nicht berechtigt waren, dem Manager diese Informationen mitzuteilen.

Um die Metapher zu erweitern: In meiner stereotypen und unrealistischen Welt sind Erzähler (Ansichten) hübsch, aber mit leerem Kopf und glauben oft alles, was Sie ihnen sagen. Sicherheitsbeamte / Empfangsmitarbeiter sind minimal höflich, aber nicht sehr sachkundig, aber sie wissen, wo die Leute sollten und sollte nicht gehen und Manager sind wirklich hässlich und gemein, wissen aber alles und können sagen, was wahr ist und was nicht.

srboisvert
quelle
4

Eine Sache, die beim richtigen Trennen hilft, ist das Vermeiden des Anti-Patterns "Lokale Variablen vom Controller an das View übergeben". An Stelle von:

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

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

end

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

Versuchen Sie, es auf einen Getter zu verschieben, der als Hilfsmethode verfügbar ist:

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

Dies macht es einfacher zu ändern, was in "@foo" eingefügt wird und wie es verwendet wird. Es vergrößert die Trennung zwischen Controller und Ansicht, ohne sie komplizierter zu machen.

James A. Rosen
quelle
ähm ... Yuk. Können Sie bitte einige gute Gründe / Szenarien hinzufügen, wann Sie dies tun würden? Dies bricht KISS und YAGNI und ist sehr stinkend (nur um noch ein Klischee zu werfen)
Sixty4Bit
2
1) Rails macht viel Magie, um die Instanzvariablen des Controllers in Ihre Ansichtsinstanz zu kopieren. 2) Die vorgeschlagene Implementierung lädt auch nur foo, wenn auf sie zugegriffen wird, was manchmal Arbeit sparen kann. Die wichtige Antwort ist jedoch 1).
Webmat
11
Seufz Das ist schrecklich. Die gemeinsame Nutzung von Rails-Instanzvariablen ist eine Funktion, die kein Anti-Pattern ist. Es ist ein allgegenwärtiger syntaktischer Zucker mit geringem mentalem Overhead, der selten oder nie Probleme in der realen Welt verursacht. Wenn Sie es nicht mögen, gut, aber das Codieren mit einer nicht standardmäßigen Barockstruktur macht die Dinge unendlich schlimmer. In diesem Fall machen Sie foo effektiv zu einer globalen (ohnehin pro Controller) Variablen. Der Versuch, einen wahrgenommenen Missbrauch des variablen Umfangs durch eine dramatische Erweiterung des Umfangs zu korrigieren, ist äußerst ironisch.
GTD
1
Ich kaufe es nicht, dasil003. Der Umfang von foound von @fooist derselbe - beide sind auf das Paar <ControllerClass, request> beschränkt. Darüber hinaus kann ich mithilfe der Getter-Version ändern, wie dieses FooObjekt gefunden / gespeichert / zwischengespeichert wird, ohne zu ändern, wie die Ansicht darauf zugreift.
James A. Rosen
1
Ich denke, Sie meinen "Instanzvariablen übergeben" Anti-Pattern. Eine Instanz var leckt den Status für das gesamte Rendering, selbst in tief verschachtelten Partials. Ihre Lösung leckt ebenfalls den Status, ist jedoch etwas besser als eine Instanzvariable, da keine Neuzuweisung möglich ist. Das Übergeben eines Lokals ist eigentlich das Beste, weil es so ist, als würde man eine Methode aufrufen. Das Lokale kann von Partials nicht gesehen werden. Siehe diese Antwort .
Kelvin
2

Nun, es hängt irgendwie davon ab, womit sich die Logik befassen muss ...

Oft ist es sinnvoll, mehr Dinge in Ihre Modelle zu stecken und die Controller klein zu lassen. Dies stellt sicher, dass diese Logik problemlos von jedem Ort aus verwendet werden kann, an dem Sie auf die Daten zugreifen müssen, die Ihr Modell darstellt. Ansichten sollten fast keine Logik enthalten. Im Allgemeinen sollten Sie sich also bemühen, es so zu gestalten, dass Sie sich nicht wiederholen.

Ein kurzer Blick auf Google zeigt außerdem einige konkretere Beispiele dafür, was wohin geht.

Modell: Validierungsanforderungen, Datenbeziehungen, Methoden erstellen, Methoden aktualisieren, Methoden zerstören, Methoden finden (beachten Sie, dass Sie nicht nur die generischen Versionen dieser Methoden haben sollten, sondern auch, wenn Sie viel tun, z. B. Leute mit Rot finden Haare nach Nachnamen, dann sollten Sie diese Logik extrahieren, damit Sie nur den find_redH_by_name ("smith") oder ähnliches aufrufen müssen.

Ansicht: Hier sollte es um die Formatierung von Daten gehen, nicht um die Verarbeitung von Daten.

Controller: Hier geht die Datenverarbeitung hin. Aus dem Internet: "Der Controller hat den Zweck, auf die vom Benutzer angeforderte Aktion zu reagieren, alle vom Benutzer festgelegten Parameter zu übernehmen, die Daten zu verarbeiten, mit dem Modell zu interagieren und die angeforderten Daten in endgültiger Form an den Benutzer weiterzuleiten Aussicht."

Hoffentlich hilft das.

Paul Wicks
quelle
0

In einfachen Worten, Modelle haben im Allgemeinen alle Codes, die sich auf Tabellen beziehen, ihre einfachen oder komplexen Beziehungen (denken Sie an SQL-Abfragen mit mehreren Tabellen) und die Manipulation der Daten / Variablen, um mithilfe der Geschäftslogik zu einem Ergebnis zu gelangen .

Controller verfügen über Code / Zeiger auf die relevanten Modelle für den angeforderten Job.

Ansichten akzeptieren die Benutzereingaben / Interaktionen und zeigen die resultierende Antwort an.

Jede größere Abweichung von diesen wird diesen Teil unerwünscht belasten und die Gesamtleistung der Anwendung kann beeinträchtigt werden.

Anutosh
quelle
-1

Testen, Testen ... Wenn Sie so viel Logik wie möglich in das Modell einfügen, können Sie es ordnungsgemäß testen. Unit-Tests testen die Daten und die Art und Weise, wie sie durch Testen des Modells gebildet werden, und Funktionstests testen die Art und Weise, wie sie durch Testen der Controller geroutet oder gesteuert werden. Daraus folgt, dass Sie die Integrität der Daten nur testen können, wenn sie vorhanden sind das Model.

j


quelle