Odrobina sensu w widokach i szczypta logiki

Odrobina sensu w widokach i szczypta logiki

[info] Jeśli pracujesz na laboratorium, aby rozpocząć realizację kolejnego modułu, musisz wykonać poniższe operacje

  • sklonuj repozytorium ze swoim kodem (git clone ŚCIEŻKA_DO_REPOZYTORIUM),

  • zainstaluj potrzebne gemy (bundle install --path vendor/bundle),

  • dokonaj migracji bazy danych (rails db:migrate)

  • uruchom serwer (rails server)

Niestety, nie wszystko w naszej aplikacji da się wygenerować automatycznie. W tym module zaimplementujemy więc nietypowe akcje, charakterystyczne dla naszej aplikacji, jak na przykład śledzenie kursów.

Dla wygody, najpierw rozszerzymy odrobinę prymitywny interfejs dla całej aplikacji.

Elementy obecne na każdej stronie

Uzupełniamy nagłówek w application.html.erb tak, aby móc szybko przenieść się do każdej podstrony.

<ul>
  <li><%= link_to "Strona główna", root_path %></li>
  <li><%= link_to "Kursy", courses_path %></li>
  <li><%= link_to "Studenci", students_path %></li>
  <% if logged_in? %>
    <li><%= link_to current_student.name, current_student %></li>
    <li><%= link_to "Wyloguj", logout_path, method: :delete %></li>
  <% else %>
    <li><%= link_to "Zaloguj", login_path %></li>
  <% end %>
</ul>

Lista naszych kursów i najnowszych wpisów na stronie głównej.

Uzupełniamy widok główny aplikacji (static/index.html.erb) tak, aby wyświetlał listę kursów, do których będzie zapisany aktualnie zalogowany student.

Jeśli odwiedzimy teraz stronę główną, zobaczymy, że nie jesteśmy zapisani do żadnego kursu. I nawet nie ma jak tego zrobić.

Strona kursu

Rozszerzmy więc widok kursu (views/courses/show.html.erb), dodając na nim możliwość zapisu (subskrybcji), jeśli ktoś jest właśnie zalogowany.

Śledzenie kursów

Przycisk śledzenia kursu musi odnosić się do jakiejś akcji. Rozszerzmy więc plik routingu o akcję follow w kontrolerze kursu.

Widok kursu (app/views/courses/show.html.erb) uzupełniamy o łącze do tej akcji.

Od razu dodajemy akcję follow do kontrolera kursów. Na tę chwilę niech przenosi do kursu, nie robiąc niczego więcej.

Spróbujmy więc kliknąć w link zapisywania do kursu. Niestety, nawet to jeszcze nie działa, a serwer twierdzi, że nie istnieje pole @course. Pamiętając o regule DRY, możemy zauważyć, że na początku kontrolera znajduje się dyrektywa before_action, nakazująca uruchomić metodę set_course przed wywołaniem każdej z wymienionych po niej akcji. Metoda ta odpowiada za zainicjalizowanie zmiennej @course zgodnie z parametrem id przekazanym w zapytaniu. Uzupełnijmy więc listę metod o akcję follow.

Następuje radość, ponieważ kliknięcie w zapis do kursu nie zwraca już błędu. Uzupełnijmy teraz metodę follow o faktyczne zapisywanie studenta do kursu. Robimy to przez dodanie do atrybutu courses aktualnie zalogowanego studenta (current_student) aktualnego kursu (@course).

Po przetestowaniu zapisu możemy zauważyć, że mamy możliwość zapisywania się w nieskończoność, po miliony razy do tego samego kursu. Nie brzmi to przesadnie sensownie. Dodajmy więc do modelu studenta (student.rb) metodę sprawdzającą, czy jest on do danego kursu zapisany.

Zaktualizujmy widok kursu tak, aby wyświetlał link do subskcrypcji tylko w wypadku, w który jeszcze nie jesteśmy zapisani do kursu.

Pozornie wszystko jest w porządku. Jednak, nadal możemy dokonać wielokrotnej subskrypcji wywołując przez url zapytanie /courses/1/follow. Zablokujmy więc zapisywanie się ponad stan już w samym kontrolerze.

Wspaniale. Możemy zapisać się do kursu jedynie jeden jedyny raz. Nie możemy jednak się z niego wypisać. Dodajmy więc łącze do wypisywania się z kursu.

Uzupełnijmy plik routes.rb o odpowiednią ścieżkę.

I stwórzmy odpowiednią akcję. Najpierw rozszerzmy listę metod uzyskujących aktualny kurs z metody set_course o metodę unfullow.

Następnie zaimplementujmy akcję usuwania studenta z listy zapisanych do kursu.

I działa.

Dodawanie tematów

Skoro udało nam się zrealizować obsługę zapisywania na kurs, wypadałoby również rozszerzyć nasz serwis o możliwość zakładania tematów w kursie. Na początek musimy poprawić routing zgodnie z zagnieżdżeniem, które wynika z naszego diagramu ERD. Studenci się nie zmieniają, będąc zasobem obocznym. Posty jednak, przez relację wiele do jednego, należą do tematów, a tematy, w ten sam sposób, do kursów.

Zauważmy, że przy okazji pozbyliśmy się metody index z obu zagnieżdżonych zasobów, zakładając, że wyświetlenie konkretnego kursu będzie od razu indeksować wszystkie tematy, a konkretnego tematu, indeksować wszystkie posty. Użyjmy komendy rake routes aby zobaczyć wynik zmian.

Zaktualizujmy widok kursu, aby wyświetlał listę tematów.

Przy okazji dodaliśmy do strony kursu link do tworzenia nowego tematu, wyświetlający się, jeśli student jest zapisany do kursu. Musimy również poprawić kontroler tematu tak, aby przy tworzeniu nowego kursu, pobierał z parametru course_id kurs, w którym zgodnie z URL się gnieździmy.

Z powodu zagnieżdżenia musimy również poprawić formularz tematu (app/views/topic/_form.html.erb). Dotychczas wyglądał on jak poniżej.

W poprawkach, musimy rozpocząć go od dyrektywy wskazującej zarówno kurs, jak i temat.

Poprawmy również topics/new.html.erb, aby zamiast do listy wszystkich tematów, łącze Back kierowało do strony kursu.

Na koniec poprawek, skracamy formularz tematu do niezbędnych pól. Nie musimy podawać w nim już identyfikatora studenta, ponieważ będzie on tym aktualnie zalogowanym, ani identyfikatora kursu, który pobierzemy sobie ze ścieżki.

Spróbujmy teraz wysłać nasz formularz z nowym tematem. Oczywiście nie da się go wysłać, bo występuje błąd. To metoda create. Musimy poprawić jej nagłówek, tak samo jak przy metodzie new, inicjalizując zmienną @course kursem zgodnym z tym podanym w URL-u.

Pole kursu ustawia się automagicznie w drugiej linii, a w trzeciej ręcznie przypisujemy do tematu aktualnie zalogowanego studenta. Z kolei Redirect (redirect_to) wymaga tablicy kolejnych zagnieżdżeń URL-a.

Ustawmy jeszcze od razu, przy pamięci, metodę update.

Dla poprawnego ustawiania pola @course w metodach innych niż create i update poprawmy set_topic.

Na koniec możemy zaktualizować widok tematu tak, aby wyświetlał wszystkie posty i posiadał link do tworzenia nowej odpowiedzi.

Obsługa tworzenia nowego tematu gotowa.

Dodawanie postów

Zrealizowaliśmy dodawanie tematów zagnieżdżonych w kursach. Obsłużmy jeszcze drugie zagnieżdżenie — postów do danego tematu.

Analogicznie do pierwszego zagnieżdżenia, w metodzie new wskażmy na wszystkie trzy zasoby (@course, @topic i nowy @post).

Formularz nowego posta powinien być w stanie powrócić do widoku tematu. Poprawiamy więc posts/new.html.erb tak, aby odnosił do wskazanego tematu we wskazanym kursie.

Później, sam formularz rozpoczynamy znów od dyrektywy wskazującej kolejne stadia zagnieżdżenia. (Bardzo ważna jest tutaj spacja po przecinku).

Znów skracamy sam formularz do niezbędnych pól. Tym razem potrzebne nam jest tylko zawartość (body) posta. Student będzie tym aktualnie zalogowanym, a kurs i temat pobierzemy z URL-a.

Jak poprzednio, formularza początkowo nie uda się wysłać, z powodu niepoprawnej metody create. Poprawiamy więc jej początek, analogicznie do zmian w metodzie new.

Pole kursu znów ustawia się automagicznie w drugiej linii, a studenta ustawiamy ręcznie. Redirect ponownie wymaga tablicy kolejnych złamań URL-a. Ustawmy jeszcze, przy pamięci, metodę update.

Poprawmy set_post.

I mamy w pełni działającą aplikację. Jest w niej sporo dziur i niedoróbek, ale jej schemat operacyjny jest już pełen i wystarczy spokojnie jako pierwszy projekt studencki w technologii Ruby on Rails.

[info] Aktualny kod

Na koniec każdego modułu znajduje się łącze do pełnej wersji kodu, który powinien być jego wynikiem.

Last updated