OO Design w Rails: gdzie umieścić rzeczy
Bardzo lubię Rails (choć generalnie jestem niespokojny), a Ruby jest bardzo OO. Jednak tendencja do tworzenia ogromnych podklas ActiveRecord i ogromnych kontrolerów jest całkiem naturalna (nawet jeśli używasz kontrolera na zasób). Gdybyś miał tworzyć głębsze światy obiektów, gdzie umieściłbyś klasy (i moduły, jak sądzę)? Pytam o poglądy (w samych pomocnikach?), kontrolery i modele.
Lib jest w porządku, i znalazłem jakieś rozwiązania, aby go przeładować w środowisku dev, ale chciałbym wiedzieć, czy jest lepszy sposób, aby to zrobić. Martwię się, że zajęcia będą zbyt duże. A co z silnikami i jak się do nich dopasowują?
4 answers
Ponieważ Rails zapewnia strukturę pod względem MVC, naturalnym jest używanie tylko kontenerów modelu, widoku i kontrolera, które są dla Ciebie dostępne. Typowym idiomem dla początkujących (a nawet niektórych średnio zaawansowanych programistów) jest wepchnięcie całej logiki w aplikacji do modelu (klasy bazy danych), kontrolera lub widoku.
W pewnym momencie ktoś zwraca uwagę na paradygmat "fat-model, chudy-controller" , a średniozaawansowani Programiści pośpiesznie usuwają wszystko ze swoich kontrolerów i wrzucić go do modelu, który zaczyna stać się nowym koszem na śmieci dla logiki aplikacji.
Chude Kontrolery to w zasadzie dobry pomysł, ale co za tym idzie-umieszczenie wszystkiego w modelu nie jest najlepszym planem.W Ruby masz kilka dobrych opcji, aby uczynić rzeczy bardziej modułowymi. Dość popularną odpowiedzią jest użycie modułów (Zwykle przechowywanych w lib
), które przechowują grupy metod, a następnie dołączają moduły do odpowiednich klas. Pomaga to w przypadkach gdzie masz kategorie funkcjonalności, które chcesz ponownie wykorzystać w wielu klasach, ale gdzie funkcjonalność jest nadal przypisana do klas.
Pamiętaj, że kiedy dołączasz moduł do klasy, metody stają się instancjami klasy, więc nadal kończysz z klasą zawierającą ton metod, są one po prostu ładnie zorganizowane w wiele plików.
To rozwiązanie może działać dobrze w niektórych przypadkach--w innych przypadkach, będziesz chciał pomyśleć o używaniu klas w kodzie, które są , a nie modelami, widokami lub kontrolerami.
Dobrym sposobem myślenia o tym jest "zasada jednej odpowiedzialności", która mówi, że klasa powinna być odpowiedzialna za jedną (lub małą liczbę) rzeczy. Twoje modele są odpowiedzialne za utrzymywanie danych z Twojej aplikacji do bazy danych. Kontrolerzy są odpowiedzialni za otrzymanie żądania i zwrócenie realnej odpowiedzi.
Jeśli masz pojęcia, które nie pasują do tych boxes (persistence, request/response management), prawdopodobnie chcesz pomyśleć o tym, jak modelować pomysł, o którym mowa. Możesz przechowywać nie-modelowe klasy w aplikacji/klasach lub gdziekolwiek indziej i dodawać ten katalog do ścieżki ładowania wykonując następujące czynności:]}
config.load_paths << File.join(Rails.root, "app", "classes")
Jeśli używasz passenger lub JRuby, prawdopodobnie chcesz również dodać swoją ścieżkę do eager Load paths:
config.eager_load_paths << File.join(Rails.root, "app", "classes")
Najważniejsze jest to, że gdy dojdziesz do punktu w Rails, w którym znajdziesz się zadając to pytanie, to czas wzmocnić swoje Ruby kotlety i rozpocząć modelowanie klas, które nie są tylko klasami MVC, które Rails daje Ci domyślnie.
Update: ta odpowiedź dotyczy Rails 2.x i wyżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 21:16:48
Update : użycie obaw zostało potwierdzone jako nowe domyślne w Rails 4.
To naprawdę zależy od Natury samego modułu. Zwykle umieszczam rozszerzenia controller/model w folderze / concerns w aplikacji.# concerns/authentication.rb
module Authentication
...
end
# controllers/application_controller.rb
class ApplicationController
include Authentication
end
# concerns/configurable.rb
module Configurable
...
end
class Model
include Indexable
end
# controllers/foo_controller.rb
class FooController < ApplicationController
include Indexable
end
# controllers/bar_controller.rb
class BarController < ApplicationController
include Indexable
end
/ lib jest moim preferowanym wyborem dla bibliotek ogólnego przeznaczenia. Zawsze mam przestrzeń nazw projektu w lib, w której umieszczam wszystkie biblioteki specyficzne dla aplikacji.
/lib/myapp.rb
module MyApp
VERSION = ...
end
/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb
Rozszerzenia rdzeni Ruby / Rails zwykle odbywają się w config inicjalizatory tak, że biblioteki są ładowane tylko raz na rails boostrap.
/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb
Dla fragmentów kodu wielokrotnego użytku, często tworzę (mikro)wtyczki, aby móc je ponownie wykorzystać w innych projektach.
Pliki pomocnicze zazwyczaj przechowują metody pomocnicze, a czasami klasy, gdy obiekt ma być używany przez helpery (na przykład konstruktory formularzy).
To jest naprawdę ogólny przegląd. Podaj więcej szczegółów na temat konkretnych przykładów, jeśli chcesz uzyskać bardziej spersonalizowane sugestie. :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-27 11:02:43
"Ogromny" to niepokojące słowo... ;-) Jak twoi kontrolerzy stają się wielcy? To jest coś, na co powinieneś spojrzeć: idealnie, Kontrolery powinny być cienkie. Wybierając zasadę kciuka z powietrza, sugerowałbym, że jeśli regularnie masz więcej niż, powiedzmy, 5 lub 6 linijek kodu na metodę kontrolera( działanie), to twoje kontrolery są prawdopodobnie zbyt grube. Czy jest powielanie, które może przenieść się do funkcji pomocnika lub filtra? Czy istnieje logika biznesowa, która może zostać zepchnięta w dół do modeli?... tendencja do robienia ogromnych Podklasy ActiveRecord i ogromne kontrolery są całkiem naturalne ...
Jak twoje modelki stają się ogromne? Czy należy szukać sposobów na zmniejszenie liczby obowiązków w każdej klasie? Czy są jakieś typowe zachowania, które można wyodrębnić do mixins? Lub obszary funkcjonalności, które możesz delegować na klasy pomocnicze?
EDIT: staram się trochę rozszerzyć, mam nadzieję, że nie zniekształca niczego zbyt źle...
Pomocnicy: live w app/helpers
i są najczęściej używane do uproszczenia widoków. Są albo specyficzne dla kontrolera (dostępne również dla wszystkich widoków dla tego kontrolera), albo ogólnie dostępne (module ApplicationHelper
w application_helper.rb).
Filtry: powiedzmy, że masz ten sam wiersz kodu w kilku akcjach (dość często, pobieranie obiektu za pomocą params[:id]
lub podobnych). Duplikacja ta może być najpierw abstrakcyjna do osobnej metody, a następnie całkowicie usunięta z akcji poprzez zadeklarowanie filtra w definicji klasy, np. before_filter :get_object
. Zobacz też Sekcja 6 w ActionController Rails Guide niech programowanie deklaratywne będzie twoim przyjacielem.
Modele Rails nie muszą być podklasami ActiveRecord:: Base. Albo Inaczej mówiąc, model nie musi być analogiem tabeli, ani nawet związany z czymkolwiek przechowywanym. Nawet lepiej, jeśli nazwiesz swój plik app/models
zgodnie z konwencjami Rails ' a (wywołaj # underscore na nazwie klasy, aby się dowiedzieć jakie Rails będzie szukał), Rails go znajdzie bez żadnych require
niezbędnych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-05 19:11:51
Oto doskonały wpis na blogu o refaktoryzacji grubych modeli, które wydają się wynikać z filozofii "cienkiego kontrolera":
Http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Podstawowa wiadomość to "nie wyodrębniaj Mixinów z modeli Fat", zamiast tego użyj klas usług, autor dostarcza do tego 7 wzorców
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-15 07:58:45