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ą?

Author: Dan Rosenstark, 2009-07-01

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.

 375
Author: Yehuda Katz,
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. :)

 61
Author: Simone Carletti,
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

... tendencja do robienia ogromnych Podklasy ActiveRecord i ogromne kontrolery są całkiem naturalne ...

"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?

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.

[7]}Refaktoryzacja modeli jest trochę bardziej Religijna. Uczniowie wujka Boba zasugerują, na przykład, abyś przestrzegał pięciu przykazań solidnego . Joel i Jeff mogą polecić bardziej "pragmatyczne" podejście, chociaż wydawali się być później trochę bardziej pogodzeni. Znalezienie jednej lub więcej metod w ramach klasy, która operowanie na jasno zdefiniowanym podzbiorze jego atrybutów jest jednym ze sposobów identyfikacji klas, które mogą być refakturowane z modelu pochodnego ActiveRecord.

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 requireniezbędnych.

 10
Author: Mike Woodhouse,
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

 1
Author: bbozo,
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