Parę pytań dot. helperów i partiali

Hej!
Ostatnio masę się naczytałem o tym, że railsowe helpery to zło i dobrze jest z nich zrezygnować na rzecz np. dekoratorów. Tworząc partiala napotkałem kilka wątpliwości i chciał bym Was zapytać jak rozwiązujecie tego typu problemy i jakie są “best practices” w takim wypadku.

Otóż, powiedzmy że tworzymy sobie sklep internetowy. Renderując listę produktów, dla każdego produktu używamy partiala _product.html.slim, w którym renderowane są: tytuł, cena, opis i zdjęcie. Chciał bym, aby ten partial był używany w różnych miejscach aplikacji i żeby jego wygląd był możliwie jak najbardziej konfigurowalny (poprzez przekazywanie różnych parametrów przy renderowaniu). Dla przykładu, chciał bym aby możliwa była konfiguracja rozmiaru zdjęcia produktu. Parametry partiala, w przypadku ich nie podania, powinny mieć swoje domyślne wartości (np. jeśli ktoś nie określi rozmiaru zdjęcia, to partial powinien użyć rozmiaru 100x100) Do głowy przychodzą mi cztery rozwiązania:

  1. Używanie OR dla wszystkich wystąpień parametrów

     = image_tag product.image.url, width: width || 100, height: height || 100
    

    To oczywiście beznadziejna opcja bo w kodzie jest okropny bałagan plus jeszcze przydało by się sprawdzać, czy zmienne width i height w ogóle istnieją (nie jestem teraz pewien na 100% ale pewnie by się powyższy kod wysypał w razie ich braku)

  2. Zdefiniowanie na początku helpera wszystkich zmiennych i ich wartości domyślnych

     width ||= 100
     height ||= 100
     = image_tag product.image.url, width: width, height: height
    

    Markdown mi na to nie pozwala ale dwie pierwsze linijki powinny zaczynać się znakiem -. Ta opcja wygląda całkiem spoko ale dla prostych partialów. Przy ich rozroście robi się syf no i ogólnie te pierwsze linijki chyba nie powinny znajdować się w widoku.

  3. Stworzenie helpera, który renderuje mi ten sam markup co mój wcześniejszy partial. To wydaje mi się całkiem fajne bo trzymam wszystkie “logiczne” aspekty poza widokiem. Niestety pisanie bardziej skomplikowanego markupu za pomocą “helperowych helperów” (content_tag etc.) to trochę katorga…więc nie.

  4. Stworzenie helpera, który używa przy renderowaniu swojego własnego widoku. Nie wiem czy to nie jest jakaś programistyczna zbrodnia ale wydaje mi się to “najczystsze” z wszystkich czterech opcji. Logika w metodzie, markup w widoku, super.

O ile ostatnie dwie opcje podobają mi się najbardziej (a w zasadzie to głównie ostatnia), ze względów wspomnianych w pierwszym akapicie chyba nie powinienem w ogóle używać helperów do niczego. Powinienem je wywalić z projektu i używać dekoratorów. A dekoratory się do powyższego zastosowania kompletnie nie nadają.

Pytanie - jak zrobić to najlepiej / najwygodniej / najpoprawniej ? Jak zrobilibyście / robicie to Wy ?
Z góry dzięki za pomoc!

Mój pomysł to:
Definiujesz klasy: np full, small, thumbnail i to przekazujesz do partiala.

   render partial: 'product', locals: { size: 'small' }

W partialu w divie lub img ustawiasz klasę przekazaną w size

<div class="product #{size}">produkt</div>

A jak to ma wyglądać definiujesz w css.

.small {
 width: 100px;
 height: 100px;
 }

Dzięki temu rozdzielasz logikę od wyglądu. I w kodzie nie pętają ci się jakieś zmienne/stałe.

Poszedłbym o krok dalej - stworzenie całej klasy ViewModelu dla każdego widoku/modelu (wszystko zależy od taktyki jaką chcesz przyjąć). Helper przekazywałby do widoku tylko jeden obiekt (ViewModel).
Gemy: https://github.com/drapergem/draper , https://github.com/apotonick/cells albo stworzenie czegoś pod siebie (albo własny gem, albo tworzenie samemu klas).

O ile w przypadku renderowania np samego zdjęcia, to użycie deokratora/viewmodelu jest faktycznie nadmiarowe.
Jednak coś na tyle skomplikowanego jak produkt (który ma wiele atrybutów, może kiedyś jakieś relacje do tego), to jak najbardziej sensowne rozwiązanie.

1 Like

o! Cells wygląda świetnie : ) Na bank z tego skorzystam. Wielkie dzięki!

@musashimm mniej więcej tak to właśnie zawsze robiłem ale problem polega na tym, że jeśli pojawi się więcej takich parametrów (15?) to robi się lekki syf bo muszę gdzieś określić wartości domyślne (np. dla Twojego size)