Zanim przystąpimy do pracy, musimy skonfigurować bazę danych. Ponieważ pracujemy bez użycia Railsów, konieczne jest
ręczne zestawienie połączenia oraz stworzenie odpowiednich tabel w bazie. Zadania te realizowane są przez
skrypt db_setup.rb
. Aby go uruchomić wpisujemy
$:.unshift "."
require 'db_setup'
W dalszych zadaniach będzie wykonywać polecenia korzystając z następujących klas, zmapowanych na odpowiadające im table w bazie danych:
class Author < ActiveRecord::Base
# name (string)
# surname (string)
# born (datetime)
# died (datetime)
# image_url (string)
has_many :books
end
class Book < ActiveRecord::Base
# title (string)
# language (string)
# author (Author)
# published (integer)
belongs_to :author
has_and_belongs_to_many :genres
end
class Genre < ActiveRecord::Base
# name (string)
has_and_belongs_to_many :books
end
Cztery podstawowe operacje, które wykonujemy na danych to
W skrócie oznaczane są one za pomocą akronimu CRUD.
W ActiveRecord (w skrócie AR) korzystamy z obiektowego interfejsu. Tworzenie danych wygląda następująco:
author = Author.new(name: "Adam", surname: "Mickiewicz")
author.save
Innymi słowy tworzymy nowy obiekt Rubiego i wywołujemy na nim metodę save
. To że faktycznie został on dodany do bazy danych
możemy zweryfikować wyszukując pierwszy obiekt w bazie:
author = Author.first
puts author.name
puts author.surname
Dodaj do bazy 3 autorów:
Odczytywanie danych z bazy można realizować na wiele sposobów. Najprostszy sposób, to wyszukiwanie ich z wykorzystaniem
klucza główego - id
. Służy do tego metoda find
:
author = Author.find(1)
puts author.surname
author = Author.find(2)
puts author.surname
Wykorzystanie tej metody może jedak skutkować wyjątkiem, jeśli w bazie nie ma wiersza z danym kluczem:
author = Author.find(10)
Możemy zabezpieczyć się przed tą sytuacją, korzystają z innego wywołania find_by_id
author = Author.find_by_id(10)
p author
Próba odczytania pól takiego obiektu, również skończy się wyjątkiem. Co należy zrobić, żeby wypisać imię i nazwisko autora
wyłącznie wtedy gdy autor istnieje w bazie? Zaimplementuj metodę print_author
, która radzi sobie z tym problemem.
def print_author(id)
end
# te linijki mają pozostać niezmienione
print_author(1)
print_author(10)
Modyfikowanie danych realizowane może być na kilka sposobów. W pierwszej kolejności możemy zmodyfikować atrybut obiektu i następnie zapisać go do bazy
author = Author.find(1)
puts author.surname
author.surname = "Mickiewiczowski"
author.save
other_author = Author.find(1)
puts other_author.surname
Można również skorzystać z metody update_attributes
, która działa podobnie jak konstruktor, ale dane są od razu
modyfikowane w bazie
author = Author.find(1)
author.update_attributes(name: "Wojciech")
other_author = Author.find(1)
puts other_author.name
Zmodyfikuj wszystkich autorów, tak by ich daty urodzenia i śmierci były poprawne. Popraw również imię i nazwisko Adama Mickiewicza.
Aby wprowadzić datę skorzystaj z metody Date.parse
.
Usuwanie danych realizowane jest za pomocą wywołania destroy
:
author = Author.find(1)
author.destroy
Ponieważ właśnie usunąłeś/ęłaś Adama Mickiewicza, ponownie utwórz odpowiadający mu rekord.
find
, first
, last
, all
¶Metoda find
pozwala nie tylko pobierać pojedynczy obiekt z bazy, ale również kilka obiektów na raz:
authors = Author.find(2,3,4)
authors.each do |author|
puts "#{author.name} #{author.surname}"
end
Metody first
oraz last
zwracają odpowiednio pierwszy i ostatni rekord w bazie. W domyślnej konfiguracji kolejność
ta będzie odpowiadała czasowi ich utworzenia.
puts Author.first.surname
puts Author.last.surname
Natomiast metoda all
zwraca kolekcję obejmującą wszystkie rekordy w bazie danych:
authors = Author.all
authors.each do |author|
puts "#{author.name} #{author.surname}"
end
Wypisz wszystkich autorów znajdujących się w bazie wraz z ich datami urodzenia i śmierci. Postaraj się sformatować daty,
tak by obejmowały tylko dzień, miesiąc i rok - w tej kolejności. Służy do tego metoda strftime
.
find_by
¶AR definiuje również metody pozwalające na wyszukiwanie rekordów na podstawie wartości atrybutów. Najprostsza z nich to find_by
. Zwraca rekord, które posiada wartość określoną w zapytaniu:
author = Author.find_by_name("Adam")
puts author.surname
where
¶Metoda where
odpowiada klauzuli where
z języka SQL. Podstawowa różnica polega na tym, że wartości poszczególnych pól określamy w postaci par klucz-wartość. Jeśli chcemy uzyskać pojedynczy wynik dodajemy metodę first
lub last
:
author = Author.where(name: "Eliza").first
puts author.surname
Metoda ta ma jednak znacznie większe możliwości - można np. podawać zakresy wartości, jako zakresy Rubiego:
authors = Author.where(born: (Date.parse("1780-1-1")..Date.parse("1800-12-31"))
authors.each do |author|
puts "#{author.name} #{author.surname} #{author.born.strftime("%d-%m-%Y")}"
end
Metodę where
można wywoływać wielokrotnie. Wtedy wyniki są łączone za pomocą operatora koniunkcji. Jeśli chcemy
użyć innego operatora (np. OR
lub LIKE
), konieczne jest użycie nieco innej składni:
authors = Author.where("name LIKE 'A%'")
authors.each do |author|
puts author.surname
end
Jeśli dane w napisie przekazanym do metody where
pochodzą od użytkownika aplikacji, to narażamy się na atak SQL-injection.
Aby go unikąć, wartość podaną przez użytkownika przekazujemy jako osobny argument, np.
name = "Adam"
authors = Author.where("name = ?",name)
authors.each do |author|
puts author.surname
end
W tej sytuacji AR sam zadba o odpowiednią konwersję znaków "niebezpiecznych".
Znajdź i wypisz wszystkich autorów, którzy zmarli między rokiem 1800 a 1900.
order
¶Do określania kolejności wyników służy metoda order
. Działa ona analogicznie do klauzuli ORDER
w języku SQL.
authors = Author.order(:born)
authors.each do |author|
puts "#{author.name} #{author.surname} #{author.born}"
end
Metoda ta często jest łączona z wywołaniami first
i last
author = Author.order(:born).last
puts "#{author.name} #{author.surname} #{author.born}"
Znajdź autora, który zmarł jako ostatni.
limit
i offset
¶Metody limit
i offset
działają analogicznie jak ich odpowiedniki w SQL:
Author.limit(2).each do |author|
puts "#{author.name} #{author.surname} #{author.born}"
end
Author.offset(2).each do |author|
puts "#{author.name} #{author.surname} #{author.born}"
end
Warto jednak pamiętać, żeby stosując je określić pożądek rekordów.
Znajdź i wypisz 3 autorów, którzy zmarli jako pierwsi.