Prezenter w Railsach

Cześć, mam mały problem z wybraniem jakiegoś sensownego podejścia do tworzenia prezentera. Ogólnie problem mam taki, że na widokach mam za dużo logikii, chciałem ją przenieśc do Prezentera i tu spotkałem się z X sposobami, na które ten pattern jest rozpisywany na przeróżnych blogach. Dość często można znaleźć podejści, w którym Prezentery są implementowane z wykorzastaniem Drapera, jednak nie podoba mi się takie podejście (ściśle związane z jednym modelem). ( Wydaje mi się to problematyczne, jeżeli z widoku chaiłbym przenieść jakieś warunki związane z więcej niż 1 modelem). Wpadłem na taki artykuł: https://www.happybearsoftware.com/rails-presenters-for-readable-modular-and-testable-code
Na podstawie tego podejścia, chciałem rozpisać Prezenter per page, nie per model. i w nim mieć metody zgodnie z zasadą “Tell don’t ask” takie jak np.

def show_awesome_message?
  if model1.present? && model2.sold? && model3.sth
     I18n.t("awesome_message1")
 elsif model2.present?
     I18n.t("awesome_message2")
 end
end

ale i też np parsowanie danych przez nokogirii

  def parsed_informations
    Nokogiri::HTML::DocumentFragment.parse(model1.informations).to_html
  end

i w takim podejściu w kontrolerze przekazywałbym modele i prezentery, które bym wykorzystywał na stronie.
Tu też znalazłem podejście, w którym przypisanie modeli zawiera się w prezenterze:
https://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/
Ale nie wiem czy prezenter powinien być za to odpowiedzialny i czy w przypadku, gdy korzystałbym na widoku z wielu modelii nie lepiej użyc Fasady i tam dodać te przypisania.
I pytanie główne jest takie, czy nie mieszam w tym momencie design patternów i jakie powinno być właściwe podejście do tego tematu :stuck_out_tongue:

99.9999% dekoratorów to moduły … Drapper jest cięzki

:thinking: czyli każdy User ma swój zestaw stron do zaprezentowania (dynamiczny CMS) :thinking:

jest fajny blog za i przeciw fasadzie

Opakowanie da Ci możliwość swobodnej “adaptacji wnętrza” - też zależy od opakowanie :stuck_out_tongue:

Zapisz sobie na różne sposoby

  • przekazanie modeli/prezenterów
  • użycie w ramach render <- nie wiem czy finalnie chcesz mieć jeszcze katalog app/views :upside_down_face:

i porównaj każdy:

:heavy_plus_sign: ile swobody Ci daje?
:heavy_minus_sign: jak mocno wiąże ręce? <- mix patternów

Trudno być bardziej precyzyjnym nie znając pełnego kontekstu uzycia


Myślałeś o jakimś lżejszym frameworku ruby ?

To akurat legacy code, ale ogólnie myślałem podoba mi się podejście z trailblazera

Zgadzam sie, ale z drugiej strony w aplikacji sa już dekoratory oparte o drapera :stuck_out_tongue:

Nie nie jest to CMS, jakby treści zależały od usera, to chyba dodałbym jakiegoś visitora :thinking:
Problem mam taki, że jest widok, na którym mam zbyt dużo logikii i zalezności pomiędzy różnymi modelami. Chciałem przenieść tą logikę w inne miejsce ,żeby “nie zalegała” na widokach, są to widoki railsowe w app/views i np. na widoku miałem takie warunki podobne do:

if model1.present? && model2.sold? && model3.sth || model4.visited?
     I18n.t("awesome_message1")
 elsif model2.present?
     I18n.t("awesome_message2")
 elsif
      I18n.t("awesome_message3")
 end
end

i np. warunkowe wyświetlanie treści,zależne od ram czasowych omiędzy dniem dzisiejszym, a np datą utworzenia, modyfikacji itp i typu uzytkownika - to akurat przeniosłem do Policy Objectu. Te warunki nie pasują mi do helperów ani już tym bardziej do decoratora, dlatego pomyślałem, żeby utworzyć prezenter i tu własnie, nie chce tworzyć prezentera do konkretnego modelu, tylko do konkretnego widoku, ze względu na zależność od więcej niż jednego modelu i tego,że na jednej stronie np.awesome_message może różnić się od warunków na jej wyświetlanie na innym widoku ( tylko uproszczony przykład na szybko ). Z drugiej strony nie chcę sie przez refactor zapędzić i stworzyć jakąś hydrę :skull:

Aktualne podejście daje mi swobodę użycia, większa część logikii znikneła z widoków :smiley:

Tu jest problem właśnie, bo tego jeszcze nie wiem, a nie chce, żeby zabolało w przyszłości :worried:

Jeżeli ten sam PolicyObject może być użyty w innym PresenterObject - zakładam że może - to fasada jest OK jako wrap interfejsu dla śrubki z nakrętką :wink:

nie można zrefaktorować wszystkiego od razu - hybrydy nie unikniesz - chyba że :timer_clock: klient pozwoli :timer_clock:

:partying_face: Nie przejmujesz się problemami o których jeszcze nie wiesz :partying_face:

Klient za 2 tygodnie od dziś zmieni w wymaganiach and na or

…od tego jest … :keyboard: refactor day :keyboard:

… czasem… więcej niż day :frowning:

ciężkie refaktory się zgłasza w skrajnych przypadkach wchodzi w grę złagodzenie wymagań

dodaj taski oflagowane refactor klient musi wiedzieć co jest grane i dlaczego - zadecydować kiedy przeznaczyć na to czas

No tak zgadza się, a jak ogólnie oceniasz takie podejście, że tworzę ten Presenter per Page?

Tak bez patrzenia w kod to…

:heavy_plus_sign: Dobry z punktu widzenia cząstkowych refaktorów łatwo wydzielić stare/nowe

:heavy_plus_sign: wszystko jest lepsze od wciskania warunków w widoku :wink:

:heavy_plus_sign: Fasada per widok, następny krok, sinatra, roda ? :stuck_out_tongue:

:heavy_minus_sign: Nie wszystkie widoki mają złożoność Homepage e-sklepu - wymagają aż fasady

:heavy_minus_sign: Napewno wyjdzie w praniu że UserPresenter będzie bardziej potrzebny niż UserListPresenter

:heavy_minus_sign: :thinking: reszta kontekstu o którym nie wspomniałeś :smiley:

Iteracja rządzi - w tej iteracji chcesz wysprzątać widoki - powodzenia

1 Like

Dzięki za pomoc :grinning:, zobaczymy w praktyce jak to wyjdzie

wyjdzie… że prezentery są całkiem OK… ale… nie każde opakowanie to fasada :blush:

Może Cells ?

Myślałem nad tym, ale wydaje mi się, że wprowadzenie tego do istniejącej aplikacji, jest gorszym pomysłem niż dodanie prezenterów.

jest gorszym pomysłem

ponieważ? koszt wejścia?

Nie zamierzam refaktoryzować wszystkich widoków i wydaje mi się, że dodanie prezentera nie zaburzy spójności pomiędzy tym co już jest w aplikacji i jest to według mnie szybsze do ogarnięcia niz cells. Cells byłyby według mnie fajnym rozwiązaniem gdyby były użyte w całym projekcie, a nie w 2-3 widokach i mam wrazenie, że stworzenie prezentera jest szybsze i w sumie nawet bardziej mi się podoba ten pattern niż cellsy

To wajcha w drugą stronę :sunglasses:. Little Decorator.
W sumie gem zawiera jeden plik…

Takie podejście odrzuciłem, ze względu na to, że uzywam na widokach więcej niż jednego modelu i niechciałem dekorować wszystkich modelii, których uzywam na widoku. dodałem prezenter, który bardziej skupia się na konkretnym widoku bez żadnych gemów, przekazuje do niego obiekt, które chcę uzyć na widoku, do atrybutów modelii odnoszę się poprzez “delegate to” i dodaję w nim metody odpowiedzialnę za logike. W aplikacji też mam dekoratory i tam używam drapera, nie chciałem trzymać części prezentacyjnej w decoratorze, też zastanawiałem sie czy nie uzyć do tego drapera, ale nie podoba mi się to że w takim podejściu delegowane są wszystkie atrybuty modelu