Rails Model, View, Controller e Helper: cosa va dove?


155

In Ruby on Rails Development (o MVC in generale), quale regola veloce dovrei seguire su dove mettere la logica.

Per favore, rispondi affermativamente: con Do metti questo qui , invece di non metterlo lì .

Risposte:


173

MVC

Controller : inserisci qui il codice che ha a che fare con l'elaborazione di ciò che un utente desidera e la decisione su cosa fornire, capire se sono connessi, se devono vedere determinati dati, ecc. Alla fine, il controller esamina le richieste e stabilisce quali dati (modelli) mostrare e quali viste visualizzare. In caso di dubbi sul fatto che il codice debba essere inserito nel controller, probabilmente non dovrebbe esserlo. Mantieni i tuoi controller magri .

Vista : la vista deve contenere solo il codice minimo per visualizzare i tuoi dati (modello), non dovrebbe eseguire molte elaborazioni o calcoli, dovrebbe mostrare i dati calcolati (o riepilogati) dal modello o generati dal controller. Se il tuo View ha davvero bisogno di eseguire elaborazioni che non possono essere eseguite dal Modello o dal Controller, inserisci il codice in un Helper. Un sacco di codice Ruby in una vista rende difficile il markup delle pagine.

Modello : il tuo modello dovrebbe essere dove risiede tutto il tuo codice relativo ai tuoi dati (le entità che compongono il tuo sito, ad esempio Utenti, Posta, Account, Amici ecc.). Se il codice deve salvare, aggiornare o riepilogare i dati relativi alle tue entità, inseriscili qui. Sarà riutilizzabile su viste e controller.


2
Le persone stanno iniziando ad allontanarsi dal modello grasso. Mi piace pensare al mio modello come a una struttura di dati. Quindi scrivo alcuni oggetti Ruby che implementano il comportamento, inizializzandolo con il modello (tratta il modello come i suoi dati nello stesso modo in cui potresti trattare stringhe e matrici come dati negli oggetti al di fuori di Rails). Ecco un buon video con un esempio di questa tecnica.
Joshua Cheek,

@AdamDonahue Non sono sicuro che qualcosa di grasso possa essere visto come una buona cosa. Tonnellate di responsabilità sono meglio appartenenti ai servizi.
Fatuhoku,

35

Per aggiungere alla risposta di Pauliephonic:

Helper : funzioni per facilitare la creazione della vista. Ad esempio, se stai sempre iterando su un elenco di widget per visualizzare il loro prezzo, inseriscilo in un aiuto (insieme a un parziale per la visualizzazione effettiva). O se hai un pezzo di RJS che non vuoi ingombrare la vista, mettilo in un aiuto.


In realtà non inseriamo anche il metodo sign_in in Helper? Come suggerito RoR Tutorial qui >>> ruby.railstutorial.org/book/…
Ivan Wang

14

Il modello MVC riguarda davvero solo l'interfaccia utente e nient'altro. Non è necessario inserire alcuna logica aziendale complessa nel controller poiché controlla la vista ma non la logica. Il Titolare dovrebbe occuparsi della selezione della vista corretta e delegare elementi più complessi al modello di dominio (Modello) o al livello aziendale.

Domain Driven Design ha un concetto di servizi che è un luogo in cui si attacca la logica che deve orchestrare una serie di vari tipi di oggetti, il che significa generalmente logica che non appartiene naturalmente a una classe Model.

In genere penso al livello di servizio come all'API delle mie applicazioni. I livelli dei miei servizi di solito si associano abbastanza da vicino ai requisiti dell'applicazione che sto creando, quindi il livello di servizio agisce come una semplificazione delle interazioni più complesse rilevate nei livelli inferiori della mia app, vale a dire che potresti raggiungere lo stesso obiettivo bypassando i livelli di servizio ma dovresti tirare molte più leve per farlo funzionare.

Nota che non sto parlando di Rails qui sto parlando di uno stile architettonico generale che affronta il tuo problema particolare.


Questa è un'ottima risposta :)
Carlos Martinez,



7

Inserisci elementi relativi al controllo di autorizzazione / accesso nel controller.

I modelli riguardano tutti i tuoi dati. Convalida, relazioni, CRUD, business logic

Le visualizzazioni riguardano la visualizzazione dei dati. Visualizza e ottieni solo input.

I controllori riguardano il controllo di quali dati vanno dal modello alla vista (e quale vista) e dalla vista al modello. I controller possono esistere anche senza modelli.

Mi piace pensare al controller come a un addetto alla sicurezza / receptionist che ti indirizza il cliente (richiesta) allo sportello appropriato dove fai una domanda a un cassiere (visualizza). Il cassiere (visualizza) quindi va e ottiene la risposta da un manager (modello), che non vedi mai. La richiesta quindi torna alla guardia giurata / addetto alla reception (controller) e attendi fino a quando non viene indirizzato a un altro cassiere (visualizza) che ti dice la risposta che il direttore (modello) ha detto loro in risposta alla domanda dell'altra cassiere (visualizza) .

Allo stesso modo, se vuoi dire qualcosa al cassiere (visualizza), allora succede la stessa cosa, tranne che il secondo cassiere ti dirà se il gestore ha accettato le tue informazioni. È anche possibile che la guardia di sicurezza / centralinista (responsabile del trattamento) ti abbia detto di fare un'escursione poiché non eri autorizzato a comunicare al gestore tali informazioni.

Quindi, per estendere la metafora, nel mio mondo stereotipato e irrealistico, i narratori (opinioni) sono carini ma a testa vuota e spesso credono a tutto ciò che dici loro, gli addetti alla sicurezza / receptionist sono minimamente educati ma non sono molto ben informati ma sanno dove le persone dovrebbero e non dovrebbe andare ei manager sono davvero brutti e cattivi, ma sanno tutto e possono dire cosa è vero e cosa non lo è.


4

Una cosa che aiuta a separare correttamente è evitare l'anti-pattern "passa variabili locali dal controller per visualizzare". Invece di questo:

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

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

end

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

Prova a spostarlo su un getter disponibile come metodo di supporto:

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

Ciò semplifica la modifica di ciò che viene inserito in "@foo" e di come viene utilizzato. Aumenta la separazione tra controller e vista senza renderli più complicati.


uhmmm ... Yuk. Potete per favore aggiungere alcuni buoni motivi / scenari per quando lo fareste. Questo rompe KISS e YAGNI ed è molto puzzolente (solo per
aggiungere

2
1) Rails fa molta magia per copiare le variabili di istanza del controller nella tua istanza di visualizzazione. 2) L'implementazione suggerita carica anche foo solo se vi si accede, il che può far risparmiare un po 'di tempo. La risposta importante è davvero 1), però.
webmat

11
Sospiro Questo è terribile. La condivisione delle variabili dell'istanza di Rails è una caratteristica e non un modello. È uno zucchero sintattico onnipresente, a bassa mente mentale che raramente, se non mai, causa problemi nel mondo reale. Se non ti piace, va bene, ma codificarlo con una struttura barocca non standard rende le cose infinitamente peggiori. In questo caso stai effettivamente trasformando in una variabile globale (per controller comunque). Il tentativo di correggere un abuso percepito di scoping variabile aumentando notevolmente l'ambito è estremamente ironico.
gtd

1
Non lo sto comprando, dasil003. L'ambito di fooe di @foosono gli stessi - entrambi sono ambiti alla coppia <ControllerClass, request>. Inoltre, utilizzando la versione getter, posso cambiare il modo in cui l' Foooggetto viene trovato / memorizzato / memorizzato nella cache senza cambiare la modalità di accesso alla vista.
James A. Rosen,

1
Penso che intendi l'anti-pattern "passa variabili d'istanza". Un'istanza var perderà lo stato per l'intero rendering, anche nei partial profondamente nidificati. Anche la tua soluzione perde stato, ma è leggermente migliore di un'istanza var perché non consente la riassegnazione. Passare un locale è in realtà il migliore perché è come chiamare un metodo; il locale non può essere visto dai parziali. Vedere questa risposta .
Kelvin,

2

Beh, dipende in qualche modo da ciò che la logica ha a che fare con ...

Spesso ha senso spingere più cose nei tuoi modelli, lasciando i controller piccoli. Ciò garantisce che questa logica possa essere facilmente utilizzata da qualsiasi luogo sia necessario per accedere ai dati rappresentati dal modello. Le viste non dovrebbero contenere quasi nessuna logica. Quindi davvero, in generale, dovresti sforzarti di farlo in modo da non ripetere te stesso.

Inoltre, un breve pezzo di google rivela alcuni esempi più concreti di ciò che va dove.

Modello: requisiti di convalida, relazioni con i dati, creazione di metodi, aggiornamento di metodi, distruzione di metodi, ricerca di metodi (notare che non si dovrebbero avere solo le versioni generiche di questi metodi, ma se c'è qualcosa che si sta facendo molto, come trovare persone con il rosso capelli per cognome, quindi dovresti estrarre quella logica in modo che tutto ciò che devi fare è chiamare find_redH_by_name ("smith") o qualcosa del genere)

Visualizza: questo dovrebbe riguardare la formattazione dei dati, non l'elaborazione dei dati.

Controller: qui è dove va il trattamento dei dati. Da Internet: "Lo scopo del responsabile del trattamento è rispondere all'azione richiesta dall'utente, prendere tutti i parametri impostati dall'utente, elaborare i dati, interagire con il modello e quindi passare i dati richiesti, in forma finale, al Visualizza."

Spero che aiuti.


0

In termini semplici, generalmente, i Modelli avranno tutti i codici relativi alle tabelle, alle loro relazioni semplici o complesse (pensali come query sql che coinvolgono più tabelle), manipolazione dei dati / variabili per arrivare a un risultato usando la logica aziendale .

I controller avranno codice / puntatori verso i modelli rilevanti per il lavoro richiesto.

Le viste accettano l'input / interazione dell'utente e visualizzano la risposta risultante.

Qualsiasi grande deviazione da questi metterà a dura prova quella parte e le prestazioni complessive dell'applicazione potrebbero essere influenzate.


-1

Test, Test ... Metti quanta più logica possibile nel modello e sarai in grado di testarlo correttamente. I test unitari testano i dati e il modo in cui sono formati testando il modello, mentre i test funzionali testano il modo in cui vengono instradati o controllati testando i controller, quindi ne consegue che non è possibile testare l'integrità dei dati a meno che non siano in il modello.

j

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.