Witajcie, czy jest możliwość wygenerowania w jednym kontrolerze kilku widoków które korzystają ze swoich kontrolerów i modeli a następnie przypisanie ich do zmiennych ?
ogólnie chodzi mi o to aby mieć 2-3 kontrolery z których każdy odpowiada np. za inny sposób pokazania jakiegoś fragmentu strony (np. listy zdjęć / czy artykułów)
Następnie chciałbym mieć jeden widok w którym mam np. 30 różnych miejsc i ręcznie do każdego z tych miejsc mógłbym wstawiać wygenerowany kod z kontrolerów.
Problem z jakim się zmagam wziął się stąd że mam na stronie głównej top 5 czytanych artykułów, jakąś mini galerię najciekawszych zdjęć i jeszcze kilka innych (bloków sekcji) - a każdy z tych elementów może występować w kilkunastu różnych wersjach które się zmieniają w zależności od pory roku dnia nastroju admina - chciałbym to jakoś sensownie ogarnąć.
@gogiel rouzmiem że render_anywhere może nam wygenerować jedynie widok ? o kontrolerze czy modelu które pobiorą specjalne dane nie mam mowy ?
kurcze zastanawiam się jak w takim razie to funkcjonuje w cms-ach gdzie mamy w jednym katalogu kilkanaście pluginów (widok kontroler model) i wstawiamy je w odpowiednim miejscu na stronę… via joomla, wordpress etc.
@mgebala8 możesz tworzyć dla każdego komponentu osobne klasy - nie ma problemu, żeby gadały one z modelami.
Kontroler to jedynie pośrednik pomiędzy HTTP a Ruby. Zamiast klas od zera można użyć Rails Cells, które dają MVC.
W joomli controller mają tylko komponenty i możesz mieć w danym widoku tylko jedną akcje jednego kontrolera. Oprócz tego możesz mieć w danym widoku umieszczony moduł ktory najwyżej będzie korzystał z akcji swojego kontrolera po ajaxie. Pluginy nie mają osobnych kontrollerów dokładasz nimi tylko coś do komponentów. Jako moduł możesz użyć w railsach partiala. Dane z modelu musisz pobrać w danej akcji kontrolera lub po ajaxie z dowolnego kontrolera.
CMSy mają często inną strukturę niż MVC. Ale problem jednego rendera per strona jest dosyć częśty u ludzi przychodzących z innych języków więc postaram się opisać koszerne rozwiązanie tego problemu na przykładzie widgetów właśnie.
Najprostszym rozwiązaniem jest używanie partiali. Te można spokojnie generować/renderować na kopy.
Kod który normalnie wylądowałby wtedy w kontrolerze pakujemy do osobnego zestawu klas - Widżetów.
Tworzymy po prostu w app katalog widgets i po restarcie zerwera pakujemy tam wszelkie widgety. Na koniec dodajemy helpera który pomoże nam tworzyć wszystkie widgety i renderować je w widokach lub kontrolerach.
Np:
page_count_widget.rb
class GuestCounterWidget
def initialize(options={})
@options=options
end
# tu zwracamy ścierzkę do widoku widgeta. Należy pamiętać że musi się ona zaczynać od _ np. _black.html.erb
def view
"widgets/guest_counter/#{@options[:style] || 'default'}"
end
# Tu zwracamy zmienne lokalne dostępne w widoku takiego widgeta. Uzywamy tylko zmiennych lokalnych (zmiast zmiennych instancji zaczynających się od @ żeby upewnić się że nie będzie żadnych interakcji pomiędzy widgetami, nawet jeśli będą to różne instancje widgetów tej samej klasy tylko z innymi opcjami.
def prepare
# tutaj przygotowywujemy wszystkie mozliwe dane ptrzebne widgetowi i zwracamy jako hash
{foo: 1, bar: 'baz', opt: @options[:size]}
end
end
widget_helper.rb pomoże nam renderować widgety w widokach in kontrolerach.
class WidgetHelper
def render_widget(widget_class, options={})
widget = widget_class.new(options)
render partial: widget.view, locals: widget.prepare
end
po czym w widoku lub kontrolerze najnormalniej w świecie:
render_widget GuestCounterWidget, style: 'black'
# albo bardziej rozbudowany przykład renderujemy widgety dla danego slota
slot.widgets.each do |widget_name, options|
render_widget widget_name.constantize, options
end
Używając partiali i wyłączając logikę renderowania do osbnych klas widgetów można bez problemu sobie poradzić z modułowymi stronami bez potrzeby bardziej skomplikowanych rozwiązań w rodzaju cells.
Należy zwrócić uwagę że klasa “Widget” pełni tutaj rolę kontrolera we wzorcu MVC, nie zawsze kontroler musi się kontroler nazywać
PS. Kod pisany na metaforycznym kolanie więc moga być literówki albo lekkie przeinaczenia ale ma głónei na celu wskazanie sposobu rozwiązania problemu. W razie problemów lub dalszych pytań pisz w tym wątku postaram się pomóc
Nie ma problemu. Jeżeli potrzebujesz naprawdę zwrócić zawartość widoku do łancucha jeste też metoda render_to_string ale przez dekadę pracy w railsach użyłem jej chyba tylko raz.
Po opisie zarówno problemu jak i odpowiedzi mam wrażenie, że tak naprawdę szukasz tego (cellek). W twoim wypadku metody renderujące będą lądowały różne widoki, ale dane i zestaw metod-helperów będzie ten sam. Daj znać jeśli potrzebujesz wyjaśnienia jak z tego korzystać