Proszę o wyjaśnienie kilku spraw związanych z zasadami funkcjonowania frameworka.
Może źle rozumiem ale wydawało mi się, że ApplicationController mogę traktować jako front kontroler i zmienne w nim ustawione będą widoczne we wszystkich kontrolerach potomnych jak też widokach z nich wywoływanych. Niestety nic z tego.
(…)
def set_theme
# select theme for site @theme = Settings[‘theme’]
prepend_view_path File.join(RAILS_ROOT, ‘app/views’, @theme)
end
end[/code]
Zmienna @theme jest widoczna w kontrolerach i widokach i jest to zrozumiałe bo metoda set_theme jest dziedziczona przez kontrolery potomne.
Ale co zrobić ze zmienną @site_defaults?
Jak widać zamiast set_theme mogłbym dać set_defaults ale nie o to chodzi. Chciałbym dowiedzieć się jak to zrobić aby zmienne ustawiane w ApplicationController były widoczne w widokach.
@site_defaults = Settings.all
To jest chyba wykonywane tylko raz, przy łądowaniu aplikacji, z kolei set_theme jest uruchamiane przy kazdym wywolaniu strony, wiec poprawnie ustawia zmienna @theme.
Ogólnie to kwestia samego Ruby’iego, a nie frameworku.
Aczkolwiek niech ktoś bardziej światły się wypowie, bo ja nie jestem tego pewien.
Bardziej potrzebujesz wyjaśnienia kilku podstawowych zasad object-oriented programming
Możesz zacząć od różnicy pomiędzy klasą a obiektem (instancją klasy) oraz analogicznych różnic typu zmienna klasowa, zmienna instancyjna, zmienna lokalna.
Dziękuję za odpowiedzi choć nie uzyskałem wyjaśnienia. “Poczytaj o podstawach programowania obiektowego w Rubim” w niczym nie pomaga. Gdybym wiedział czego szukać to oczywiście bym poszukał i nie zawracał głowy. Wprawdzie znalazłem ciekawy dokument ( http://railstips.org/2006/11/18/class-and-instance-variables-in-ruby ) ale nie wyjaśnia wszystkich wątpliwości. @hosiawak: w pierwszym przykładzie @site_defaults jest ustawiana ale dostępna jest nie przez metody obiektowe tylko klasowe klasy, w której ta zmienna jest ustawiana. Trzeci przykład również nie daje oczekiwanych rezultatów.
def initialize
super
@site_defaults = Settings.all
end
(…)[/code]
Nadal jednak nie załapałem w jaki sposób zmienne obiektowe z kontrolerów stają się zmiennymi obiektowymi widoków. A może to nie są zmienne obiektowe?
Dostałeś trochę więcej wskazówek niż to. I serio nadrób te zaległości.
Obie Fernandez “The Rails Way”, jeden z pierwszych rozdziałów.
Dobra, streszczę Ci Generalnie to jedno z tych miejsc, gdzie railsy mają trochę “magii” – otóż po zakończeniu przetwarzania kontrolera i zainicjalizowaniu widoku, wszystkie zmienne instancyjne (te z @) są kopiowane z kontrolera do analogicznych zmiennych widoku.
Zmienne klasowe, czyli @@, co prawda są widziane ze wszystkich instancji kontrolera, ale nie są już kopiowane do instancji widoku, stąd zachowanie które zauważyłeś.
Dlaczego klasa w ruby może mieć zmienną instancyjną, niemającą nic wspólnego ze zmiennymi instancyjnymi obiektów (instancji) tej klasy – patrz pierwszy akapit.
Zatem trzeba ustawiać zmienną instancyjną, jeśli ma być dostępna w widokach. Zrobienie tego dla wszystkich można osiągnąć albo metodą podaną przez Hosiawaka (bardzo “rubiowa” ), albo – bardziej railsowo – opakować w metodę i dodać ją do before_filter.
Poczytaj więcej o klasach. Tak się składa, że w Rubim klasy to też obiekty, tyle, że klasy Class.
Jak masz konstrukcję rodzaju:
class A
@b = "b"
end
To @b jest zmienną instancyjną klasy A (nie jest “zwykłą” zmienną instancyjną, ani też zmienną klasową). Dlatego jest widoczna w metodach klasowych, bo są do de facto metody singletownowe (czyli metody definiowane per obiekt) odpowiednich klas (czyli obiektów klasy Class, przypominam).
Inna sprawa, że w interakcji między kontrolerem a widokiem jest trochę magii - i za tym stoją Railsy. Po prostu wszystkie zwykłe zmienne instancyjne (czyli zmienne pojawiające się w definicjach metod instancyjnych, zawierające jeden @), są kopiowane do widoków. Pozwala to w prosty sposób przekazać odpowiednie wartości do widoków.
Swoją drogą nie dziwię się, że czytając informacje na temat metod klasowych i instancyjnych nie znalazłeś informacji na ten temat. Po prostu “zmienne instancyjne klas” (czyli zmienne z jednym @ pojawiające się w ciałach klas a nie metod) raczej nie są tam omawiane. Wykorzystywane są zazwyczaj do meta programowania i innych zaawansowanych zagadnień. Swoją drogą zastanawiam się skąd wpadłeś na pomysł aby zrobić to co opisałeś powyżej.
Dopiero co uczę się Rails i mam taki problem. W widoku ‘wiadomości’ chcę użyć metody z kontrolera ‘uzytkownika’. W kontrolerze ‘użytkownika’ napisalem helper_method :list_students, ale jak chce użyć tego w widoku ‘wiadomości’ to wyskakuje błąd, że metoda niezdefiniowana.
A czy ‘wiadomości’ są jednym z widoków kont. ‘użytkownika’? Zgduję, że nie. Lepiej chyba umieścić tę metodę w ApplicationController i tam dać helper_method. Generalnie jednak upewnij się, czy taka metoda jest Ci faktycznie potrzebna - raczej powinieneś odpowiednio ustawić zmienne w kontrolerach, a nie korzystać z metod pomocniczych typu “list_students”.
Ale w innym kontrolerze niz ‘Users’ nie moge korzystac z danych z tabeli ‘users’. Może czegoś nie rozumiem, bo dopiero co zaczynam z Rails. Więc jak mógłbyś mi tak wyjaśnić bardziej.
Robię taką metodę w kontrolerze Users: def list_students
@students = User.find :all, :conditions => { user.role => "Student" }
end
i pisze helper_method :list_students no i w widoku ‘Messages’ nie widzi mi tej metody.
Ale tu jest mowa o dwóch różnych rzeczach - czym innym jest “helper_method”, która zasadniczo nie służy do tego, co chcesz zrobić.
Po prostu w kontrolerze MessagesController możesz zrobić coś takiego (np. w metodzie show)
def show
#...
@students = User.find(:all, ...)
#...
end
A potem w widoku messages/show:
# na przykład
<%- for student in @students %>
<%= student %>
<%- end %>
Poczytaj więceję o podstawach Railsów, bo bez tego pójdziesz zupełnie nia tą drogą co trzeba.
Mam taki problem w kontrolerze. Mam dwie metody:[code]def remove
binContent
for message in list_messages
if current_user.id == message.id_recepient && @id_message == message.id
mess.update_attribute(‘recepient_delete’, true)
end
if current_user.id == message.id_sender && @id_message == message.id
message.update_attribute(‘sender_delete’, true)
end
end
end
def binContent
for message in list_messages
if message.id.to_s == params[:par] @id_message = message.id
end
end
end[/code]
Chciałem żeby @id_message z binContent było widoczne w metodzie remove. Gdy w innych metodach tak robiłem wszystko działało, jakoś teraz nie chce…
remove wykonuje sie po nacisnieciu przycisku, a binContent to mam tez taki widok.