Schemat modelu danych

[info] Materiał wideo

Poniższy materiał instruktażowy trwa dziesięć minut i zawiera w sobie materiał z modułów Tworzymy nową aplikację Ruby on Rails oraz Schemat modelu danych.

Schemat modelu danych

Właściwą pracę rozpoczniemy od stworzenia modelu danych dla naszej aplikacji. Przypominając zarys projektu, potrzebny będzie zasób dla Studenta, Kursu, Tematu oraz Posta. Podobnie jak w wypadku każdej innej aplikacji realizującej realizującej logikę biznesową, zasoby te będą zapisywane w tabelach relacyjnej bazy danych.

Podczas tworzenia schematu danych, wygodnie jest posiadać narzędzie do jego wizualizacji. Wśród gemów instalowanych w standardzie z nową aplikacją nie ma takiego, więc mamy niecodzienną okazję nauczyć się, jak instalować nowe.

Do określania listy wszystkich wymaganych w aplikacji gemów służy plik Gemfile. Proszę go otworzyć i w sekcji development dodać wpis:

gem 'rails-erd'

Samo dodanie wymagania nie oznacza oczywiście jeszcze zainstalowania modułu. Aby to uczynić, powtórzymy komendę, którą już raz wykonywaliśmy.

  • bundle install --path vendor/bundle

[info] Wskazówka

Po instalacji nowych gemów, zawsze warto uruchomić ponownie serwer. Aby go wyłączyć używamy kombinacji klawiszy Ctrl+C.

Teraz możemy przystąpić do tworzenia naszego modelu. W pierwszym kroku, korzystając z techniki nazywanej scaffoldingiem, utworzymy model Studenta, który będzie posiadać dwa pola tekstowe. Imię, czy też nazwę użytkownika w parametrze name oraz numer indeksu w parametrze index.

  • rails generate scaffold Student index:string name:string

Odwiedźmy teraz aplikację. Po pierwszej zmianie w modelu, na ekranie pojawia się błąd.

Serwer informuje nas o tym, że błąd polega na nieprzeprowadzonej migracji. Zarządzanie schematem bazy danych w wypadku aplikacji Ruby on Rails polega na odtwarzaniu go na podstawie kolejnych zmian wprowadzanych przez programistę. Zmiany takie nazywamy migracjami.

Kiedy korzystamy ze scaffoldingu, migracje tworzą się samodzielnie. Odnajdź pierwszą, odpowiedzialną za stworzenie modelu Studenta, w katalogu db/migrate.

Powyższy kod tworzy nową tabelę, o nazwie students, a w niej pola index oraz name (typu string). Dodatkowo, w standardzie dodawane są do niej również stemple czasowe, dla daty utworzenia i daty ostatniej modyfikacji zasobu (t.timestamps). Przeprowadźmy więc migrację, używając w terminalu komendy.

  • rails db:migrate

Po ponownym odwiedzeniu aplikacji wszystko powinno być już jak należy.

Kilka kroków wcześniej dodaliśmy do aplikacji gem rails-erd. Pozwala on (pod warunkiem, że w systemie operacyjnym zainstalowany został program Graphviz) na budowanie graficznego schematu zależności pomiędzy modelami zapisywanymi w bazie danych. Schemat budujemy komendą.

  • rails erd

Wynik zapisuje się w pliku erd.pdf. Na tę chwilę model jest prymitywny i opisuje jedynie jeden zasób.

Skoro jednak mamy już ten zasób, nauczmy się z niego korzystać. Obok serwera www, do naszej aplikacji możemy dostać się także z poziomu konsoli/interpretera. Uruchamiając ją w trybie piaskownicy, mamy pewność, że żadne z wykonanych przez nas modyfikacji danych nie zapiszą się w bazie na stałe.

  • rails console --sandbox

Spróbujmy utworzyć nowego, pustego użytkownika.

  • Student.create()

Niepokojące jest to, że udało się nam utworzyć pusty wpis w bazie. Ale spokojnie, zajmiemy się tym później. Sprawdźmy jeszcze, czy potrafimy dodać wypełnionego użytkownika.

  • Student.create(index: 171039, name: 'Zenek')

Zanim jednak zatroszczymy się o odpowiednie zabezpieczenie bazy danych przed wypełnianiem jej kompletnymi głupotami, zajmijmy się uzupełnieniem jej schematu. Skoro mamy już przygotowany schemat użytkownika, wygenerujmy jeszcze rusztowanie dla kursu.

  • rails generate scaffold Course name:string code:string description:string

Nie możemy zapomnieć o migracji i aktualizacji schematu.

  • rails db:migrate

  • rails erd

Nasz schemat składa się już z dwóch klas/tabel. Nie są one jednak ze sobą połączone. System zakłada, że w systemie mamy wiele kursów i wielu studentów. Każdy student może zapisać się do wielu kursów, a w konsekwencji na każdy kurs zapisanych jest wielu studentów. Potrzebujemy więc zatroszczyć się o relację [wiele do wielu](https://en.wikipedia.org/wiki/Many-to-many_(data_model)). Relację wiele do wielu w bazach relacyjnych rozwiązuje się przy użyciu tablic asocjacyjnych. Jeśli nie wiesz, czym jest tablica asocjacyjna, szybko kogoś zapytaj. Ale po cichu, bo to odrobinę wstydliwe.

Migracje bazy danych można utworzyć również ręcznie. Skorzystajmy z generatora, który stworzy nam pustą migrację tworzącą tabelę asocjacyjną students_courses.

  • rails generate migration CreateStudentsCourses

Odnajdź migrację w projekcie (katalog db/migrate). Musimy ją odrobinę zmodyfikować. Po pierwsze, wpisy w tablicy asocjacyjnej nie potrzebują przesadnie własnego indeksu, więc rezygnujemy z jego generowania, negując atrybut id. Dodajmy za to dwie kolumny, odpowiedzialne za nawiązanie (belongs_to) kolejno do tablicy students i course.

Jak pewnie się już domyślasz, po zadeklarowaniu migracji, należy ją przeprowadzić.

  • rails db:migrate

Tworzenie relacji w aplikacjach Ruby on Rails jest dwupoziomowe. Poza odpowiednim przygotowaniem bazy danych, same klasy modelu muszą zostać uzupełnione o informacje o oczekiwanej relacji. Odwiedź więc plik modelu Studenta (app/models/Student.rb) i poinformuj go o relacji wiele do wielu z kursami.

Istotne jest to, aby pamiętać o wskazaniu join_table — naszej tablicy asocjacyjnej. Jeśli tabela nazywa się student_courses, aplikacja domyśli się, jeśli poprosimy ją o wszystkie kursy danego studenta. Niestety, sama z siebie nie będzie potrafiła zlokalizować na podstawie takiej nazwy wszystkich studentów zapisanych na dany kurs.

Analogicznie uzupełnij też model kursu (Course.rb). Następnie zaktualizuj graf ERD.

  • rails erd

Możemy teraz dodać brakujące modele. W ich wypadku zaistnieją już wyłącznie wskazania wiele do jednego, które jest znacznie prostsze w implementacji, bo nie wymaga tablic asocjacyjnych. Najpierw zajmijmy się tematem, który posiada jeden łańcuch, będący miejscem na pytanie (title), wskazania studenta, będącego autorem tematu (student) oraz kursu, względem którego pytanie jest zadane (course). Relacje proste realizujemy przez zadeklarowanie przy generowaniu typu references.

  • rails generate scaffold Topic title:string student:references course:references

Następnie wygenerujmy model posta, poza treścią, wskazującego na autora i temat.

  • rails generate scaffold Post body:string student:references topic:references

Jak po każdej zmianie w bazie danych, dokonujemy migracji.

  • rails db:migrate

Aby zakończyć pracę nad modelem, upewnijmy się jeszcze co do poprawności relacji wskazanych w klasach każdego typu. Kurs (Course.rb) ma wskazywać na wielu studentów, zapisanych do niego i wiele założonych w nim tematów.

Student (Student.rb) ma wskazywać na wiele kursów, do których jest zapisany, wiele tematów, które założył i wiele postów, które napisał.

Temat (Topic.rb) ma wskazywać na studenta, będącego jego autorem, kurs, w którym został założony i wiele napisanych w nim postów.

Z kolei post (Post.rb) ma wskazywać na studenta, będącego jego autorem oraz temat w którym go napisano.

Po migracji bazy i upewnieniu się co do zawarcia w modelu wszystkich oczekiwanych relacji, budujemy schemat.

  • rails erd

Gratulacje! Mamy gotowy model danych.

[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