Dwa pytania

Witam. Bawię się aktualnie Railsami i przy klepaniu prostej stronki stwierdziłem, że muszę się o pewne rzeczy zapytać mądrych głów :wink:

  1. Czy w MVC absolutnie wszystkie zmienne wykorzystywane w widoku muszą być deklarowane w kontrolerze? Czy zadeklarowanie np. jakiejś zmiennej pomocniczej w widoku jest niewłaściwe?
  2. Jak w Railsach wygląda sprawa z wydajnością jeśli chodzi o pojedynek: deklaracja zmiennej w widoku vs deklaracja zmiennej w kontrolerze? Czy czas realizacji żądania będzie taki sam dla zadeklarowanych 10000 zmiennych w widoku i zadeklarowanych 10000 zmiennych w kontrolerze?

Jest możliwe, ale doświadczenie uczy że gryzie w najmniej oczekiwanym momencie (może powodować trudne do zdebugowania babole). Oczywiście jeśli chcesz się na własnej skórze przekonać czemu separacja warstw jest lepsza niż ich mieszanie to droga wolna.

Pewnie nie, bo zmienne instancyjne kontrolera są przepisywane do zmiennych instancyjnych widoku. Ale najlepiej to zbenczmarkować!

Oraz serio masz jakiś usecase dla 10000 osobno tworzonych i nazywanych zmiennych do przekazania do widoku? Bo mi się wyobraźnia skończyła trzy zera temu…

Dzięki za szybką odpowiedź :slight_smile:

Jest możliwe, ale doświadczenie uczy że gryzie w najmniej oczekiwanym momencie (może powodować trudne do zdebugowania babole). Oczywiście jeśli chcesz się na własnej skórze przekonać czemu separacja warstw jest lepsza niż ich mieszanie to droga wolna.[/quote]
Wiem, że jest to możliwe. Wzorzec MVC nie bez powodu jest właśnie “MVC”, ale czy deklaracja zmiennych w widoku jest niedopuszczalna, czy tylko odradzana?

Pewnie nie, bo zmienne instancyjne kontrolera są przepisywane do zmiennych instancyjnych widoku. Ale najlepiej to zbenczmarkować!

Oraz serio masz jakiś usecase dla 10000 osobno tworzonych i nazywanych zmiennych do przekazania do widoku? Bo mi się wyobraźnia skończyła trzy zera temu…[/quote]
Spokojnie, 10000 zmiennych to był tylko teoretyczny przykład :wink: Po prostu byłem ciekaw i nadal jestem, więc pewnie sobie to sprawdzę w wolnej chwili :wink:

Jest możliwa i pewnie nieraz to zrobisz, chociażby w pętli. Jeśli natomiast odczuwasz potrzebę wykorzystania zmiennej w widoku, to prawdopodobnie mógłbyś ten kod schować w helperze albo lepiej w presenterze (które standardowo nie są wspierane w Rails) - tzn. dekoratorze, który opakowuje obiekt przed przekazaniem go do widoku.

Zasadniczo problemy wydajnościowe nie wiążą się z przekazywaniem zmiennych do widoku, tylko z pobieraniem danych z bazy, więc to są rozważania czysto teoretyczne.

W Ruby nigdy nie deklarujesz zmiennych, wystarczy ich inicjalizacja jakąś wartością, to raz. Deklaracje zmiennych masz w jężykach typu C czy JavaScript, gdzie mówisz “int foo;” albo “var bar;” nie koniecznie inicjując je początkową wartością.

Powinieneś w kontrolerze ustawiać mocno ograniczoną liczbę zmiennych przekazywanych do widoku, najlepiej jedną, ale nie z powodów wydajnościowych (takich nie ma raczej) a z powodu czytelności kodu.

Dobrym rozwiązaniem jest też używanie helper_method albo decent_exposure zamiast zmiennych instancyjnych, czyni to kod trochę czystszym.

Całkiem ciekawe zagadnienie z tą wydajnością, bo z jednej strony zgadzam się oczywiście, że w aplikacjach nie ma to żadnego znaczenia, ale z drugiej strony koszt przeniesienia tych zmiennych do widoku istnieje - kontroler nie jest kontekstem widoku, dlatego na samym stworzeniu zmiennej historia się nie kończy.

W Railsach zmienne instancji przekazywane są z kontrolera do widoku w postaci hasha: https://github.com/rails/rails/blob/5c1354901ec/actionpack/lib/abstract_controller/rendering.rb#L138. Później jak się tworzy “view context” (czyli to co będzie dostępne jako “self” w widoku, w railsach jest to domyślnie instancja klasy ActionView::Base), to ten hash jest przekazywany przy tworzeniu instancji: https://github.com/rails/rails/blob/5c1354901ec/actionpack/lib/abstract_controller/rendering.rb#L85

Następnie ActionView bierze tego hasha i dla każdego klucza deklaruje zmienną instancji o tej nazwie oraz nadaje jej wartość.

Jeżeli kogoś interesuje bardziej jak to działa, to tutaj są gisty z użyciem ActionView poza railsami: https://gist.github.com/drogus/2287909 i https://gist.github.com/drogus/2472931

Z ciekawości zrobiłem prosty benchmark i przypisanie 100_000 kluczy do hasha + stworzenie zmiennych instancji ( self.instance_variable_set(name, value) ) trwa ok. 0.4s

I na koniec jeszcze raz podkreślę, że w praktyce nie ma to żadnego znaczenia, chciałem tylko uściślić jak to dokładnie działa, bo dla mnie jest to ciekawy temat.