Nil.object, czyli jak wyświetlić listę elementów na każdej stronie

Czołem,

bardzo zielona szkoła, bo najpewniej zapomniałem o “najpodstawowszej” rzeczy, o której się dało.
Anyway, mam problem niemal identyczny do opisanego w wątku: http://rubyonrails.pl/forum/t42-Jak-pisac%3F , tj. chciałem, żeby w całej aplikacji pojawiała się lista istniejących kategorii.
W views/layouts/application.html.erb wrzuciłem zatem:

<% @categories.each do |category| %> <%= link_to category.title, category_path(category.id) %> <% end %>
a w application_controller.rb:

@categories = Category.all

Niestety, efekt jest niezadowalający, ponieważ Rails raczy mnie błędem (przykładowo):

[code]NoMethodError in Photos#show

Showing /home/jaqbeu/dev/rails/firerescue/app/views/layouts/application.html.erb where line #13 raised:

You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each[/code]
(i dalej linijki z application.html.erb, się rozumie).

Dodatkowo, żeby nie było, że @categories zwraca nil, bo naprawdę nic nie ma, to w innym widoku, w skrócie X (zrobionym “na potrzeby”) jest taki sam kod, jak w application.html.erb i w XController#index również jest @categories =… i tam działa to normalnie, tj. wyświetla kategorie.

Zakładam zatem, że najpewniej powinienem to @categories w ApplicationController wrzucić w jakąś funkcję, tylko za bardzo nie mam pomysłu w jaką, żeby kategorie wyświetlały się na każdej stronie…

Będę wdzięczny za dowolnego rodzaju wskazówkę, bo nawet nie mam pomysłu, jak to ugryźć… :slight_smile:

Rails 3.0.3, jeśli to może mieć wpływ.

Pozdrawiam
jaqbeu

Jestem szybszy od Was w udzielaniu sobie odpowiedzi, ale nie będę kasował, bo może trafi się jeszcze jeden taki zawodnik… :slight_smile:

W application_controller.rb wystarczyło zrobić tak:

[code ruby] before_filter :defaults

def defaults
@categories = Category.all
end[/code]

i działa cacy na każdej stronie. :slight_smile:

Ewentualnie jak to nie tylko to, albo tak się nie robi, to będę wdzięczny za wyprowadzenie z błędu.

… tak się nie robi ;-). Niepotrzebnie przypisujesz te kategorie do @categories. Problem pojawi się wtedy, gdy będziesz miał CategoriesController z akcją index, gdzie utworzysz kolejną zmienną @categories (nadpiszesz ją).

<% Category.all.each do |category| %> <%= link_to category.title, category_path(category.id) %> <% end %>

A właśnie że nie robi się tak jak ty napisałeś. Standardową zasadą MVC jest nie wołać bezpośrednio modelu z widoku!. Więc chłopak zrobił dobrze, najwyżej co może zrobić to nadać zmiennej bardziej semantyczne brzmienie typu @categories_for_menu etc.

Nie chce mi się flejmować, ale dzięki named scope’om wywoływanie metod modelu w widoku jest często najlepszym, najprostszym – i wbrew pozorom najczystszym – rozwiązaniem. Zakładając że nie mamy ochoty babrać się z Cellsami do głupiego menu z kategoriami po lewej stronie.

Mi to się wydaję (na ile umiem ;)), że to zależy od sytuacji. Tutaj spokojnie mogę sobie to wywołać w widoku, bo tej listy kategorii będę używał tylko tutaj, zatem deklarowanie tego w kontrolerze wymaga za dużo roboty, bo muszę jeszcze nazwę wymyślić i o niej pamiętać. :wink:
Za to na pewno nie wywoływałbym w widoku czegoś w stylu:

Gallery.where(:category_id => params[:category_id])

bo to by zwyczajnie brzydko wyglądało i w tym wypadku raczej nie miałoby sensu (po to są kontrolery chyba).
Sposób qoobaa mi jak najbardziej działa i spełnia swoje zadanie (dzięki! :)), więc w tym wypadku spokojnie mogę sobie trochę okroić kod.