, Štefan Húska

Pomenované varianty v Active Storage: prečo prestať písať helper metódy na model

Pôvodná implementácia vyzerala takto — tri metódy, každá s vlastnými rozmermi:

def variant_cover
  file.variant(resize_to_fill: [600, 400])
end

def variant_medium
  file.variant(resize_to_limit: [1200, 1200])
end

def variant_full
  file.variant(resize_to_limit: [2400, 2400])
end

Problém nie je v tom, že by to nefungovalo. Problém je v tom, že rozhodnutia o spracovaní obrázkov — čo je infraštruktúrna záležitosť — sú roztrúsené po business logike modelu. Navyše, ak niekde v šablóne potrebujete thumbnail, píšete image.file.variant(resize_to_fill: [150, 150]) priamo do ERB, čím sa rozmery duplikujú na viacerých miestach.

Nový prístup: varianty v bloku has_one_attached

Rails od verzie 7 umožňuje definovať pomenované varianty priamo pri deklarácii attachmentu:

has_one_attached :file do |attachable|
  attachable.variant :cover, resize_to_fill: [600, 400]
  attachable.variant :medium, resize_to_limit: [1200, 1200]
  attachable.variant :full, resize_to_limit: [2400, 2400]
  attachable.variant :thumb, resize_to_fill: [150, 150]
end

Všetky štyri varianty sú teraz na jednom mieste. Volanie v šablónach sa zjednotí na image.file.variant(:medium) namiesto image.variant_medium. Rozdiel je jemný, ale významný — variant je teraz vlastnosťou attachmentu, nie modelu. Model Image sa stará o galérie, slugy a väzby; spracovanie súborov patrí k attachmentu.

Dopad na šablóny

Zmena sa prejavila naprieč celou aplikáciou. Vo view komponentoch aj v admin paneli sa volania zjednotili:

<%# Predtým %>
<%= image_tag url_for(image.variant_medium), class: image_css %>
<a href="<%= url_for(image.variant_full) %>">

<%# Potom %>
<%= image_tag url_for(image.file.variant(:medium)), class: image_css %>
<a href="<%= url_for(image.file.variant(:full)) %>">

Najväčší prínos bol pri thumbnailoch. Predtým sa resize_to_fill: [150, 150] opakovalo v piatich rôznych ERB súboroch — v admin editácii sekcií, v galériových pickeri, v náhľadoch. Teraz všetky používajú jednoducho image.file.variant(:thumb). Ak sa niekedy rozhodnem zmeniť veľkosť thumbnailu, stačí upraviť jedno miesto v modeli.

Čo si z toho odniesť

Pomenované varianty nie sú nová funkcia — sú v Rails od verzie 7. Napriek tomu je bežné vidieť projekty, kde sa varianty definujú ako metódy na modeli alebo sa rozmery kopírujú priamo do šablón. Dôvod je jednoduchý: helper metódy fungujú a nikto nemá motiváciu ich refaktorovať.

Kľúčový argument pre pomenované varianty je single source of truth. Keď máte štyri varianty definované v bloku has_one_attached, každý nový vývojár okamžite vidí, aké veľkosti obrázkov aplikácia používa. Nemusí hľadať metódy po modeli ani grep-ovať šablóny. A hlavne — keď sa rozmery zmenia, menia sa na jednom mieste.