Rails Model, View, Controller i Helper: co gdzie jest?

155

W Ruby on Rails Development (lub ogólnie w MVC), jaką szybką regułę powinienem przestrzegać, aby umieścić logikę.

Proszę odpowiedzieć twierdząco - z Do umieść to tutaj , zamiast Nie umieszczaj tam tego .

theschmitzer
źródło

Odpowiedzi:

173

MVC

Kontroler : Wpisz tutaj kod związany z ustaleniem, czego chce użytkownik i podjęciem decyzji, co mu dać, ustaleniem, czy jest zalogowany, czy powinien widzieć określone dane itp. Na koniec kontroler sprawdza żądania i sprawdza, jakie dane (modele) pokazać i jakie widoki renderować. Jeśli masz wątpliwości, czy kod powinien trafić do kontrolera, prawdopodobnie nie powinien. Dbaj o szczupłe kontrolery .

Widok : Widok powinien zawierać tylko minimalny kod do wyświetlania danych (Model), nie powinien wykonywać wielu operacji przetwarzania ani obliczeń, powinien wyświetlać dane obliczone (lub podsumowane) przez Model lub wygenerowane przez Kontroler. Jeśli Twój widok naprawdę wymaga przetwarzania, którego nie może wykonać model lub kontroler, umieść kod w pomocniku. Dużo kodu Ruby w widoku sprawia, że ​​znaczniki stron są trudne do odczytania.

Model : Twój model powinien znajdować się w miejscu, w którym znajduje się cały kod związany z Twoimi danymi (podmioty tworzące Twoją witrynę, np. Użytkownicy, Post, Konta, Znajomi itp.). Jeśli kod musi zapisywać, aktualizować lub podsumowywać dane związane z Twoimi podmiotami, umieść to tutaj. Będzie można go ponownie używać we wszystkich widokach i kontrolerach.

pauliefoniczny
źródło
2
Ludzie zaczynają odchodzić od grubego modelu. Lubię myśleć o moim modelu jako o strukturze danych. Następnie piszę jakiś obiekt Ruby, który implementuje zachowanie, inicjalizując go z modelem (traktuje model jako dane w ten sam sposób, w jaki możesz traktować łańcuchy i tablice jako dane w obiektach poza Railsami). Oto dobry film z przykładem tej techniki.
Joshua Cheek
@AdamDonahue Nie jestem pewien, czy coś tłustego można uznać za dobrą rzecz. Tony obowiązków to lepiej przynależność do usług.
fatuhoku
35

Aby dodać do odpowiedzi Pauliephonic:

Pomocnik : funkcje ułatwiające tworzenie widoku. Na przykład, jeśli zawsze przeglądasz listę widżetów, aby wyświetlić ich cenę, umieść ją w pomocniku (wraz z częścią dla rzeczywistego wyświetlania). Lub jeśli masz kawałek RJS, którego nie chcesz zaśmiecać widoku, umieść go w pomocniku.

jcoby
źródło
Czy właściwie nie umieszczamy również metody sign_in w pomocniku? Jak zasugerował samouczek RoR tutaj >>> ruby.railstutorial.org/book/…
Ivan Wang
14

Wzorzec MVC dotyczy tylko interfejsu użytkownika i nic więcej. Nie należy umieszczać żadnej złożonej logiki biznesowej w kontrolerze, ponieważ steruje on widokiem, ale nie logiką. Kontroler powinien zająć się wyborem odpowiedniego widoku i delegować bardziej złożone rzeczy do modelu domeny (Model) lub warstwy biznesowej.

Projekt oparty na domenie ma koncepcję usług, która jest miejscem, w którym trzymasz logikę, która wymaga aranżacji wielu różnych typów obiektów, co ogólnie oznacza logikę, która naturalnie nie należy do klasy Model.

Generalnie myślę o warstwie usług jako o API moich aplikacji. Warstwy moich usług zwykle odpowiadają wymaganiom aplikacji, którą tworzę, więc warstwa usług działa jako uproszczenie bardziej złożonych interakcji występujących na niższych poziomach mojej aplikacji, tj. Możesz osiągnąć ten sam cel pomijając warstwy usług ale aby to zadziałało, musiałbyś pociągnąć o wiele więcej dźwigni.

Zauważ, że nie mówię tutaj o Railsach. Mówię o ogólnym stylu architektonicznym, który rozwiązuje twój konkretny problem.

Søren Spelling Lund
źródło
To świetna odpowiedź :)
Carlos Martinez
12

Już tutaj doskonałe wyjaśnienia, jedno bardzo proste zdanie na zakończenie i łatwe do zapamiętania:

Potrzebujemy inteligentnych modeli, cienkich kontrolerów i widoków DUMB.

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

maddin2code
źródło
7

Umieść w kontrolerze rzeczy związane z autoryzacją / kontrolą dostępu.

Modele dotyczą Twoich danych. Walidacja, relacje, CRUD, logika biznesowa

W widokach chodzi o pokazywanie danych. Tylko wyświetlanie i pobieranie danych wejściowych.

Kontrolery służą do kontrolowania, jakie dane są przesyłane z modelu do widoku (i który widok) oraz z widoku do modelu. Kontrolery mogą również istnieć bez modeli.

Lubię myśleć o administratorze jako o ochroniarzu / recepcjonistce, który kieruje klienta (prośbę) do odpowiedniego stanowiska, w którym zadajesz kasjerowi (przeglądasz) pytanie. Następnie kasjer (widok) idzie i otrzymuje odpowiedź od menedżera (modela), którego nigdy nie widzisz. Następnie zgłoś prośbę, a następnie wróć do ochroniarza / recepcjonisty (kontrolera) i poczekaj, aż zostaniesz skierowany do innego kasjera (widok), który powie ci odpowiedź, którą kierownik (model) powiedział im w odpowiedzi na pytanie drugiego kasjera (zobacz) .

Podobnie, jeśli chcesz powiedzieć kasjerowi (zobaczyć) coś, wtedy w dużej mierze dzieje się to samo, z wyjątkiem tego, że drugi kasjer powie ci, czy menedżer zaakceptował twoje informacje. Możliwe jest również, że ochroniarz / recepcjonista (kontroler) mógł zalecić Ci wędrówkę, ponieważ nie byłeś upoważniony do przekazania kierownikowi tych informacji.

Tak więc, aby rozszerzyć metaforę, w moim stereotypowym i nierealistycznym świecie osoby opowiadające (poglądy) są ładne, ale puste i często wierzą we wszystko, co im powiesz, ochroniarze / recepcjonistki są minimalnie uprzejmi, ale nie mają zbyt dużej wiedzy, ale wiedzą, gdzie ludzie powinni i nie powinni iść, a menedżerowie są naprawdę brzydcy i wredni, ale wiedzą wszystko i potrafią powiedzieć, co jest prawdą, a co nie.

srboisvert
źródło
4

Jedną rzeczą, która pomaga prawidłowo rozdzielić, jest unikanie „przekazywania zmiennych lokalnych z kontrolera do widoku” anty-wzorca. Zamiast tego:

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

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

end

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

Spróbuj przenieść to do metody pobierającej, która jest dostępna jako metoda pomocnicza:

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

Ułatwia to modyfikowanie tego, co jest umieszczane w „@foo” i jak jest używane. Zwiększa separację między kontrolerem a widokiem, nie czyniąc ich bardziej skomplikowanymi.

James A. Rosen
źródło
uhmmm ... Fuj. Czy możesz dodać kilka dobrych powodów / scenariuszy, kiedy to zrobiłbyś. To łamie KISS i YAGNI i jest bardzo śmierdzące (tylko po to, by rzucić jeszcze jeden frazes)
Sixty4Bit
2
1) Railsy robią wiele magii, kopiując zmienne instancji kontrolera do instancji widoku. 2) Sugerowana implementacja ładuje również foo tylko wtedy, gdy jest dostępna, co może zaoszczędzić trochę pracy przez pewien czas. Jednak tak naprawdę ważna odpowiedź brzmi: 1).
webmat
11
Westchnienie To straszne. Współdzielenie zmiennych instancji Railsów jest funkcją, a nie anty-wzorcem. Jest to wszechobecny cukier syntaktyczny o niskim koszcie umysłowym, który rzadko, jeśli w ogóle, powoduje problemy w świecie rzeczywistym. Jeśli ci się to nie podoba, w porządku, ale kodowanie wokół niego za pomocą barokowej niestandardowej struktury sprawia, że ​​sytuacja jest nieskończenie gorsza. W tym przypadku skutecznie tworzysz zmienną globalną foo (w każdym razie na kontroler). Próba skorygowania postrzeganego nadużycia zakresu zmiennych poprzez radykalne zwiększenie zakresu jest niezwykle ironiczna.
gtd
1
Nie kupuję tego, dasil003. Zakres fooi of @foosą takie same - oba są ograniczone do pary <ControllerClass, request>. Dodatkowo, korzystając z wersji pobierającej, mogę zmienić sposób Fooznajdowania / przechowywania / buforowania tego obiektu bez zmiany sposobu, w jaki widok uzyskuje do niego dostęp.
James A. Rosen
1
Myślę, że masz na myśli anty-wzorzec „przekazywanie zmiennych instancji”. Instancja var będzie przeciekać stan całego renderowania, nawet w głęboko zagnieżdżonych częściach. Twoje rozwiązanie również przecieka, ale jest nieco lepsze niż zmienna instancji, ponieważ nie pozwala na ponowne przypisanie. Przekazywanie lokalnego jest właściwie najlepsze, ponieważ przypomina wywołanie metody; to, co lokalne, nie jest widoczne dla stronników. Zobacz tę odpowiedź .
Kelvin,
2

Cóż, to w pewnym sensie zależy od tego, z czym ma do czynienia logika ...

Często sensowne jest umieszczanie większej liczby rzeczy w modelach, pozostawiając małe kontrolery. Gwarantuje to, że ta logika może być łatwo używana z dowolnego miejsca, w którym potrzebujesz dostępu do danych, które reprezentuje Twój model. Widoki nie powinny zawierać prawie żadnej logiki. Tak więc ogólnie powinieneś dążyć do tego, abyś się nie powtarzał.

Ponadto, krótki fragment Google ujawnia kilka bardziej konkretnych przykładów tego, co się dzieje.

Model: wymagania walidacyjne, relacje danych, tworzenie metod, aktualizowanie metod, niszczenie metod, znajdowanie metod (pamiętaj, że powinieneś mieć nie tylko generyczne wersje tych metod, ale jeśli jest coś, co robisz dużo, na przykład znajdowanie ludzi z czerwonymi włosy według nazwiska, powinieneś wyodrębnić tę logikę, aby wszystko, co musisz zrobić, to zadzwonić do find_redH_by_name ("kowal") lub coś w tym stylu)

Widok: Powinno to dotyczyć formatowania danych, a nie przetwarzania danych.

Kontroler: Tutaj odbywa się przetwarzanie danych. Z internetu: „Celem administratora jest reagowanie na działanie żądane przez użytkownika, pobranie dowolnych parametrów, które ustawił użytkownik, przetwarzanie danych, interakcja z modelem, a następnie przekazanie żądanych danych w ostatecznej formie do widok."

Mam nadzieję, że to pomoże.

Paul Wicks
źródło
0

Mówiąc prościej, generalnie modele będą miały wszystkie kody związane z tabelami, ich prostymi lub złożonymi relacjami (myślę, że są to zapytania sql obejmujące wiele tabel), manipulowanie danymi / zmiennymi w celu uzyskania wyniku przy użyciu logiki biznesowej .

Kontrolerzy będą mieli kod / wskaźniki do odpowiednich modeli dla żądanego zadania.

Widoki akceptują dane wejściowe / interakcje użytkownika i wyświetlają wynikową odpowiedź.

Każde większe odstępstwo od nich spowoduje niepożądane obciążenie tej części i może wpłynąć na ogólną wydajność aplikacji.

Anutosh
źródło
-1

Testowanie, testowanie ... Umieść jak najwięcej logiki w modelu, a będziesz mógł go poprawnie przetestować. Testy jednostkowe sprawdzają dane i sposób ich tworzenia, testując model, a testy funkcjonalne testują sposób, w jaki są kierowane lub kontrolowane przez testowanie kontrolerów, więc nie można przetestować integralności danych, chyba że są w model.

jot


źródło