Ruby on Rails.
Wprowadzenie. Wydanie II
Autor: Bruce Tate, Lance Carlson, Curt Hibbs
ISBN: 978-83-246-2210-8
Tytu³ orygina³u:
Rails: Up and Running
Format: B5, stron: 192
Poznaj Ruby on Rails
i twórz potê¿ne aplikacjeinternetowe w zaledwie kilka dni
•
Jak budowaæ dynamiczne strony, nastawione na u¿ytkownika?
•
Jak rozwi¹zaæ problemy z wydajnoœci¹ baz danych?
•
Jak sprawnie i efektywnie korzystaæ z platformy Ruby on Rails?
Dlaczego masz wybraæ Ruby on Rails? G³ównie dlatego, ¿e jest to wyj¹tkowe narzêdzie,
które umo¿liwia budowê aplikacji internetowych ka¿dego typu (w tym portali
spo³ecznoœciowych, witryn e-commerce, oprogramowania do zarz¹dzania
oraz tworzenia statystyk) w zaledwie kilka dni! A to wszystko dziêki Rails — doskonale
wyposa¿onemu frameworkowi do tworzenia aplikacji internetowych opartych o bazy
danych — który oferuje œrodowisko z wykorzystaniem jêzyka Ruby. Zaœ ten jêzyk
programowania charakteryzuje siê niezwyk³ym po³¹czeniem cech: jest równoczeœnie
prosty, elegancki i elastyczny, co pozwala dowolnie modyfikowaæ jego czêœci.
Ksi¹¿ka
„
Ruby on Rails. Wprowadzenie. Wydanie II
”
zawiera szczegó³owe porady
i wskazówki dotycz¹ce instalacji oraz korzystania z Rails 2.1, a tak¿e jêzyka
skryptowego Ruby. W podrêczniku znajdziesz nie tylko wyjaœnienia odnoœnie sposobu
dzia³ania Rails, ale równie¿ opis kompletnej aplikacji. Dziêki temu przewodnikowi
dowiesz siê, w jaki sposób wspó³pracuj¹ ze sob¹ wszystkie aplikacje tworz¹ce szkielet
Rails, a ponadto nauczysz siê sprawnie korzystaæ z dokumentacji oprogramowania
i tworzyæ zaawansowane aplikacje znacznie szybciej ni¿ dotychczas.
•
Uruchamianie i organizacja Rails
•
Budowanie widoku
•
Rusztowania, REST i œcie¿ki
•
Klasy z³o¿one
•
Rozbudowywanie widoków
•
Zarz¹dzanie uk³adem strony
•
Arkusze stylów
•
Tworzenie w³asnych funkcji pomocniczych
•
Testowanie i debugowanie
•
Tworzenie nowej aplikacji Rails
Wyczerpuj¹ce i przyjazne wprowadzenie w Ruby on Rails
3
Spis tre
ļci
Przedmowa ...............................................................................................................................5
1. Zaczynamy — wprowadzenie do Rails ........................................................................9
Uruchamianie Rails
10
Organizacja Rails
12
Serwer WWW
13
Tworzenie kontrolera
16
Budowanie widoku
18
Wiñzanie kontrolera z widokiem
20
Co siö dzieje za kulisami
22
Co dalej
23
2. Rusztowania, REST i
ļcieżki ........................................................................................25
Wprowadzenie do Photo Share
25
Przygotowanie projektu i bazy danych
27
Generowanie rusztowania zasobów
28
ćcieĔki zgodne z REST
32
Uzupeänianie rusztowania
39
Co dalej?
40
3. Podstawy Active Record ............................................................................................. 41
Podstawy mechanizmu Active Record
41
Podstawowe klasy Active Record
46
Atrybuty
48
Klasy zäoĔone
50
Zachowania
55
W kolejnym rozdziale
60
4
_
Spis tre
ļci
4. Relacje w Active Record .............................................................................................. 61
belongs_to
61
has_many
64
has_one
66
has_and_belongs_to_many
67
acts_as_list
70
Drzewa
72
O czym nie powiedzieliĈmy
75
Wybiegajñc w przyszäoĈè
76
5. Rozbudowywanie widoków ....................................................................................... 77
Obraz caäoĈci
77
Oglñdanie rzeczywistych fotografii
79
Szablony widoków
79
OkreĈlanie domyĈlnej strony gäównej
84
Arkusze stylów
85
Hierarchiczne kategorie
88
OkreĈlanie stylów dla pokazów slajdów
93
6. Ajax ..............................................................................................................................99
W jaki sposób Rails implementuje Ajax
99
Odtwarzanie pokazów slajdów
100
Zmienianie porzñdku slajdów metodñ przeciñgnij i upuĈè
103
Przeciñganie i upuszczanie wszystkiego (lub prawie wszystkiego)
107
Filtrowanie wedäug kategorii
114
7. Testowanie .................................................................................................................119
Säowo wprowadzenia
119
Mechanizm Test::Unit jözyka Ruby
120
Testowanie w Ĉrodowisku Rails
123
Asercje i testy integracyjne
140
Podsumowujñc
142
A Instalowanie Rails ..................................................................................................... 145
B Krótki leksykon Rails ..................................................................................................151
Skorowidz ............................................................................................................................. 183
25
ROZDZIA
Ĥ 2.
Rusztowania, REST i
ļcieżki
Przez stulecia rusztowania pomagaäy budowniczym w budowie i wykaþczaniu wznoszonych
budynków. ProgramiĈci równieĔ korzystajñ z tymczasowego kodu rusztowania tworzñcego
wstöpne ramy i podstawowy mechanizm aplikacji do czasu, aĔ gotowy bödzie wäaĈciwy kod
aplikacji. Rails automatyzuje proces tworzenia rusztowaþ bardzo uäatwiajñc budowanie apli-
kacji we wstöpnej fazie.
W rozdziale 1. pokazaliĈmy, jak Rails wykorzystuje tablicö z parametrami do przeksztaäcenia
prostego wywoäania Rails w wywoäanie akcji w kontrolerze. ZbudowaliĈmy w nim równieĔ
bardzo proste widoki. W tym rozdziale rozpoczniemy budowö bardziej zaawansowanej apli-
kacji, o nazwie Photo Share, która bödzie mogäa byè uĔyta do zarzñdzania fotografiami. Za-
stosujemy rusztowania do zbudowania podstawowego szablonu zawierajñcego model korzy-
stajñcy z bazy danych, kontroler oraz widok. Niejako przy okazji przedstawimy podstawy
kilku najwaĔniejszych funkcji Rails, takich jak:
x
Migracje. Ta funkcja obsäugi bazy danych pomaga programistom w wieloetapowym two-
rzeniu modelu bazy danych, zarzñdzaniu róĔnicami w schematach uĔywanych we wszyst-
kich naszych Ĉrodowiskach. Migracje korzystajñ z kodu Ruby zamiast kodu SQL specy-
ficznego dla bazy danych.
x
REST oraz zasoby. Rails korzysta intensywnie ze stylu komunikacji internetowej o nazwie
REST, czyli Representational State Transfer. Taka strategia komunikacji wykorzystujñcej
HTTP definiuje zasoby internetowe, w których kaĔde polecenie URL lub HTTP wykonu-
je jednñ z operacji CRUD (Create, Read, Update, Delete — tworzenie, odczyt, modyfikacja
i usuwanie) na zasobie. W Rails 2 kaĔdy kontroler jest zasobem REST.
x
ćcieĔki nazwane. Dla kaĔdego zasobu Rails tworzy ĈcieĔki nazwane, które odwzorowujñ
standaryzowane, eleganckie adresy URL na predefiniowane akcje kontrolera. W wyniku
tego potrzeba mniej kodu i uzyskujemy lepszñ spójnoĈè pomiödzy naszymi aplikacjami.
Przyjrzyjmy siö dokäadniej aplikacji Photo Share. Nastöpnie szybko zbudujemy podstawy tej
aplikacji. Na koniec tego rozdziaäu bödziemy mieli prostñ aplikacjö pozwalajñcñ zarzñdzaè
zdjöciami, pokazami slajdów, slajdami i kategoriami.
Wprowadzenie do Photo Share
W dalszej czöĈci tej ksiñĔki bödziemy tworzyè jednñ aplikacjö o nazwie Photo Share, umoĔli-
wiajñcñ wymianö zdjöè pomiödzy jej uĔytkownikami. Aplikacja ta bödzie korzystaäa z bazy da-
nych. Rozpoczniemy od poniĔszych prostych wymagaþ nazywanych scenariuszami uĔytkownika:
26
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
x
Umieszczanie zbioru zdjöè w sieci WWW w taki sposób, aby inni uĔytkownicy mogli je
zobaczyè.
x
Organizowanie zdjöè w kategoriach.
x
Tworzenie i przeglñdanie pokazów slajdów budowanych z dostöpnych zdjöè.
KaĔde z tych wymagaþ odnosi siö do innej czöĈci aplikacji. Przyjrzyjmy siö dokäadniej elemen-
tom Rails wymaganych przez te scenariusze.
Definiowanie zasobów
Gdy analizujemy naszñ aplikacjö, najlepiej na poczñtku myĈleè o niej jak o zasobach. Rails 2
jest Ĉrodowiskiem tworzenia oprogramowania ukierunkowanym na zasoby, wiöc tworzenie
zwykle rozpoczyna siö od zdefiniowania zasobów. Praktycznie rzecz ujmujñc, zasób jest jed-
nostkñ internetowñ, która posiada metody do reprezentowana tej jednostki i zarzñdzania niñ.
Mówiñc jeszcze praktyczniej, typowy zasób Rails jest modelem korzystajñcym z bazy danych,
kontrolerem zarzñdzajñcym tym modelem oraz widokiem, który prezentuje jeden lub wiöcej
modeli naszym uĔytkownikom. Po zdefiniowaniu wymagaþ wstöpnych nastöpnym zadaniem
jest okreĈlenie zasobów wymaganych przez naszñ aplikacjö. Spójrzmy na listö scenariuszy
i skoncentrujmy siö na rzeczownikach. Kilkoma oczywistymi kandydatami na zasoby Rails
sñ zdjöcia, slajdy, pokazy slajdów oraz kategorie. Ujawniajñ siö równieĔ niektóre relacje pomiö-
dzy nimi:
x
Kategoria zawiera wiele zdjöè, a zdjöcie moĔe mieè jednñ lub wiöcej kategorii.
x
Kategoria moĔe mieè innñ kategoriö.
x
Pokaz slajdów zawiera wiele slajdów.
x
Slajd zawiera jedno zdjöcie.
Prosty diagram, taki jak na rysunku 2.1, pomaga pokazaè zasoby aplikacji oraz relacje miödzy
nimi. W przypadku relacji „jeden do wielu” korzystamy ze strzaäki oznaczajñcej naleĔy do, wiöc
wskazuje ona od strony „jeden do wielu”. Strzaäka dwukierunkowa wskazuje relacjö „wiele
do wielu”, natomiast linie bez strzaäek — relacje „jeden do jednego”. Bödziemy korzystaè
z drzewa ze strzaäkami wskazujñcymi na klasö nadawcy. PóĒniej skorzystamy z Active Record
do definiowania relacji, ale w tym rozdziale utworzymy bardzo prosty model niezawierajñcy
zaawansowanych funkcji. Aby jednak wykonaè cokolwiek w Active Record, musimy zdefinio-
waè bazö danych.
Rysunek 2.1. Rusztowania generuj
ñce wszystkie cztery widoki
Przygotowanie projektu i bazy danych
_
27
Przygotowanie projektu i bazy danych
Zanim bödziemy mogli cokolwiek zrobiè, bödziemy potrzebowaè projektu Rails. Tworzymy
go przez wpisanie
rails photos
, a nastöpnie przechodzimy do nowego katalogu za pomocñ
cd photos
. W konsoli zobaczymy nastöpujñcy wynik (skrócony) — wynik ten moĔe byè róĔ-
ny w zaleĔnoĈci od wykorzystywanej wersji.
$ rails photos
create
create app/controllers
create app/helpers
create app/models
...
create config/database.yml
create config/routes.rb
...
$ cd photos/
JeĔeli serwer nie jest uruchomiony, naleĔy go uruchomiè ponownie za pomocñ
script/server
.
Aby upewniè siö, Ĕe wszystko dziaäa prawidäowo, naleĔy otworzyè w przeglñdarce stronö
http://localhost:3000/. JeĔeli wszystko jest w porzñdku, zobaczymy stronö powitalnñ Rails.
Przyjrzyjmy siö dokäadniej plikom, jakie Rails utworzyä dla nowego projektu. Warto zauwa-
Ĕyè, Ĕe Rails utworzyä plik konfiguracyjny bazy danych o nazwie database.yml. Od Rails 2
w domyĈlnym pliku konfiguracyjnym wykorzystywana jest lekka baza danych sqlite3. MoĔna
skorzystaè z tego silnika bazy danych lub innego, takiego jak MySQL. W tej ksiñĔce bödziemy
korzystaè z sqlite3. JeĔeli jednak zdecydujesz siö korzystaè z MySQL, bödziesz musiaä zain-
stalowaè silnik bazy danych i zmieniè plik config/database.yml, aby odpowiadaä konfiguracji
bazy danych. Powinien on wyglñdaè podobnie do przedstawionego poniĔej:
development:
adapter: mysql
database: photos_development
username: root
password:
host: localhost
test:
adapter: mysql
database: photos_development
username: root
password:
host: localhost
JeĔeli zdecydujesz siö korzystaè z MySQL lub zmieniè w jakikolwiek sposób plik database.yml,
pamiötaj, Ĕe w jözyku definicji danych YAML odstöpy sñ znaczñce. Wciöcia muszñ byè wyko-
nywane za pomocñ dwóch spacji (nie tabulatorów) i w Ĕadnym wierszu nie moĔe byè spacji
na koþcu. Szczegóäowe wskazówki na temat sposobu utworzenia dwóch baz danych, photos_
development i photos_test, moĔna znaleĒè w dokumentacji MySQL. MoĔna równieĔ uĔyè stan-
dardowej bazy i skorzystaè z domyĈlnej konfiguracji.
W czasie Ĕycia projektu korzystamy z osobnych Ĉrodowisk z oddzielnymi bazami danych, co
pozwala nam na obsäugö programowania, testowanie i instalowanie w Ĉrodowisku produk-
cyjnym. Rails ma wäasnñ strategiö obsäugi danych testowych, która zakäada usuwanie wszyst-
kich danych przed kolejnym uruchomieniem testów. Wiöcej informacji na ten temat w dalszej czö-
Ĉci rozdziaäu. Na razie wystarczy wiedzieè, Ĕe nie powinniĈmy tworzyè konfiguracji tak, aby
testowa baza danych wskazywaäa na bazö, której dane naleĔy zachowaè!
28
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
Nie naleĔy konfigurowaè testowej bazy danych jako bazy produkcyjnej lub projektowej.
Wszystkie dane z testowej bazy danych sñ zastöpowane przy kaĔdym uruchomieniu
testów.
Trzy bazy danych
Rails posiada trzy Ĉrodowiska: programistyczne, testowe i produkcyjne. ćrodowisko programi-
styczne äaduje ponownie klasy przy kaĔdym wywoäaniu nowej akcji, dziöki czemu zawsze
mamy ĈwieĔñ kopiö kaĔdej klasy, razem z najnowszymi zmianami w kodzie. W Ĉrodowisku
produkcyjnym klasy sñ äadowane jednokrotnie. W przypadku tego podejĈcia wydajnoĈè Ĉro-
dowiska programistycznego jest gorsza, ale w czasie tworzenia aplikacji natychmiast widzimy
zmiany wprowadzone w kodzie. Rails ponownie äaduje bazö testowñ przed kaĔdym urucho-
mieniem testów, co ma sens przy testowaniu, ale moĔe mieè katastrofalne skutki w Ĉrodowi-
sku produkcyjnym.
Wykorzystywane sñ równieĔ osobne bazy — programistyczna, produkcyjna i testowa. Od-
powiedzialni programiĈci nie korzystajñ z baz produkcyjnych przy pisaniu kodu, poniewaĔ
nie chcñ tworzyè, modyfikowaè lub usuwaè danych produkcyjnych. Dlaczego Rails korzysta
z osobnej, testowej bazy danych? W rozdziale 7. pokaĔemy, Ĕe w przypadku kaĔdego nowego
testu Rails tworzy nowñ kopiö danych testowych, dziöki czemu kaĔdy przypadek testowy
moĔe modyfikowaè bazö danych bez wpäywania na inne testy.
Gdy Rails generuje nowy projekt, tworzy plik o nazwie database.yml, który zawiera sekcje dla
programowania, testowana i produkcji. Konfigurujñc bazö danych nale
Ĕy pamiötaè o kilku
rzeczach. Po pierwsze, poniewaĔ Rails niszczy dane w testowej bazie danych, naleĔy siö upew-
niè, Ĕe w konfiguracji testowej nie jest wskazana baza programistyczna ani produkcyjna. Po
drugie, w pliku tym hasäa sñ zapisane otwartym tekstem. NaleĔy upewniè siö, Ĕe odpowied-
nio je obsäugujemy.
Generowanie rusztowania zasobów
Do tej pory utworzyliĈmy projekt i skonfigurowaliĈmy bazö danych. Nastöpnym krokiem
jest uĔycie rusztowania do generowania zasobów. Zaczniemy od prostego przykäadu zdjöcia.
Poczñtkowo nasze zdjöcie bödzie plikiem w systemie plików i rekordem w bazie danych
z identyfikatorem i nazwñ pliku. Nie naleĔy oczekiwaè, Ĕe Rails zbuduje kompletnñ aplika-
cjö produkcyjnñ. Generatory kodu, które próbujñ robiè wszystko, czösto powodujñ paskudne
komplikacje przy rozszerzaniu aplikacji. Potrzebujemy jedynie punktu poczñtkowego, w któ-
rym moĔemy zaczñè dostosowywanie. Utwórzmy wiöc rusztowanie dla zasobu fotografii.
Lista zdj
ýë
Generator rusztowaþ buduje model, widok, kontroler oraz testy zarzñdzajñce tym kodem. Opcje
generacji rusztowania moĔna wyĈwietliè, wpisujñc w wierszu polecenia
script/generate
scaffold
:
$ script/generate scaffold
Usage: script/generate scaffold ModelName [field:type, field:type]
Options:
--skip-timestamps Don't add timestamps to the migration file for this model
Generowanie rusztowania zasobów
_
29
--skip-migration Don't generate a migration file for this model
Rails Info:
-v, --version Show the Rails version number and quit.
-h, --help Show this help message and quit.
General Options:
-p, --pretend Run but do not make any changes.
-f, --force Overwrite files that already exist.
-s, --skip Skip files that already exist.
-q, --quiet Suppress normal output.
-t, --backtrace Debugging: show backtrace on errors.
-c, --svn Modify files with subversion. (Note: svn must be in path)
-g, --git Modify files with git. (Note: git must be in path)
...
W czasie generowaniu rusztowania moĔna podaè nie tylko nazwö modelu, ale równieĔ pola
przez niego obsäugiwane. Rusztowanie dla zdjöè generujemy w nastöpujñcy sposób:
$ script/generate scaffold photo filename:string thumbnail:string description:string
...
create app/models/photo.rb
...
create db/migrate/20080427170510_create_photos.rb
W poleceniu
script/generate
podajemy nazwö modelu i trzy kolumny potrzebne naszej apli-
kacji. Rails generuje sporo plików, w tym kontroler i kilka widoków, ale w tym momencie skon-
centrujemy siö na pliku o nazwie app/models/photo.rb oraz pliku db/migrate/20080427170510_
create_photos.rb. Liczba na poczñtku Twojego pliku create_photos.rb bödzie inna, ale reszta po-
zostanie bez zmian. Pierwszy plik zawiera model Active Record. Plik ten zawiera nastöpujñ-
cy kod:
class Photo < ActiveRecord::Base
end
Co dziwne, photo.rb nie posiada Ĕadnych informacji na temat tabeli bazy danych ani Ĕadnej
z jej kolumn. W rozdziale 3. pokaĔemy, w jaki sposób Rails odkrywa te szczegóäy. Poza mo-
delem Active Record musimy utworzyè tabelö w bazie danych. Najlepszym sposobem wyko-
nania tej operacji jest wykorzystanie migracji schematu. W czasie procesu tworzenia ruszto-
wania zasobu Rails generuje dla nas domyĈlny opis migracji. Liczba w nazwie pliku migracji
jest znacznikiem czasu. Rails korzysta z tych znaczników czasu przy przyrostowym wpro-
wadzaniu zmian do schematu bazy danych oraz wycofywaniu siö o krok, w przypadku po-
peänienia powaĔnego bäödu. Aby pokazaè, jak dziaäa migracja, na poczñtku spójrzmy, jak
wyglñda plik migracji wygenerowany przez Rails. Zajrzyjmy do pliku o nazwie db/migrate/
20080427170510_create_photos.rb:
class CreatePhotos < ActiveRecord::Migration
def self.up
create_table :photos do |t|
t.string :filename
t.string :thumbnail
t.string :description
t.timestamps
end
end
def self.down
drop_table :photos
end
end
30
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
Migracja posiada metody
up
oraz
down
. KaĔda z tych metod zmienia istniejñcy schemat bazy
danych. Metoda
up
wykonuje zmiany w przód w czasie, a
down
zmiany wstecz. MoĔna trak-
towaè metodö
up
jako polecenie wykonaj, a
down
jako polecenie wycofaj. W tym przypadku
metoda
up
tworzy tabelö, a
down
usuwa jñ. Po kaĔdej specyfikacji kolumny moĔna wskazaè
opcje pozwalajñce na okreĈlenie atrybutów tabeli, takich jak kolumny, które nie mogñ byè
puste (
:null => false
), wartoĈci domyĈlne (
:default => ""
) i podobne. Aby zobaczyè, jak
migracja wykonuje operacje, naleĔy wykonaè polecenie
rake db:migrate
:
$ rake db:migrate
(in /Users/lance/Projects/book/repo/current/src/chapter2/photos)
== 20080427170510 CreatePhotos: migrating =====================================
-- create_table(:photos)
-> 0.0047s
== 20080427170510 CreatePhotos: migrated (0.0049s) ============================
rake
to program narzödziowy Ĉrodowiska Ruby, który pomaga zarzñdzaè wszystkimi elemen-
tami zwiñzanymi z samñ aplikacjñ. Podobne narzödzia sñ dostöpne w jözyki Java (
ant
) oraz
C (
make
). W tej ksiñĔce bödziemy korzystaè z zadaþ
rake
do uruchamiania testów, äadowania
danych testowych, zmiany schematu bazy danych i wielu innych operacji. W tym przypadku
zadanie
db:migrate
wykonuje wszystkie operacje migracji, które nie byäy wczeĈniej wykona-
ne. Rails odnotowuje kaĔdñ wykonanñ migracjö w tabeli
schema_migrations
:
$ sqlite3 db/development.sqlite3
SQLite version 3.4.0
Enter ".help" for instructions
sqlite> select * from schema_migrations;
20080427170510
Wpisz
.quit
, aby zakoþczyè sqlite3.
Jak moĔna zauwaĔyè, dla kaĔdej migrowanej tabeli Rails tworzy jeden wiersz w tabeli
schema_
migrations
. Przy nastöpnym uruchomieniu
rake db:migrate
Rails wykonuje w kolejnoĈci
znaczników czasu metody
up
wszystkich migracji, które nie zostaäy odnotowane w tabeli. MoĔ-
na równieĔ wykorzystaè migracjö do cofania bazy danych. MoĔna podaè dowolny numer wersji,
wpisujñc
rake db:migrate VERSION=<znacznik_czasu>
, gdzie
<znacznik_czasu>
jest znaczni-
kiem czasu jednej z migracji. MoĔna równieĔ wykonaè metodö
up
lub
down
okreĈlonej migracji.
MoĔna to od razu wypróbowaè (trzeba pamiötaè, Ĕe w kaĔdym przypadku znaczniki czasu
bödñ inne):
$ rake db:migrate:down VERSION=20080427170510
(in /Users/lance/Projects/book/repo/current/src/chapter2/photos)
== 20080427170510 CreatePhotos: reverting =====================================
-- drop_table(:photos)
-> 0.0031s
== 20080427170510 CreatePhotos: reverted (0.0032s) ============================
$ rake db:migrate:up VERSION=20080427170510
(in /Users/lance/Projects/book/repo/current/src/chapter2/photos)
== 20080427170510 CreatePhotos: migrating =====================================
-- create_table(:photos)
-> 0.0044s
== 20080427170510 CreatePhotos: migrated (0.0046s) ============================
Mamy teraz dziaäajñcy model. Przydatne byäoby utworzenie pewnych danych testowych. Jed-
nym z najprostszych sposobów utworzenia danych testowych jest wykorzystanie osprzötu te-
stów jednostkowych w Rails. Wady i zalety testowania przedstawimy w rozdziale 7., ale teraz
po prostu dokonamy edycji pliku test/fixtures/photos.yml, aby wyglñdaä w nastöpujñcy sposób:
photo_1:
id: 1
Generowanie rusztowania zasobów
_
31
filename: train.jpg
thumbnail: train_t.jpg
description: Tym je
šdšĂ do pracy
photo_2:
id: 2
filename: lighthouse.jpg
thumbnail: lighthouse_t.jpg
description: Zawsze si
Ă tu umawiam na randki
photo_3:
id: 3
filename: gargoyle.jpg
thumbnail: gargoyle_t.jpg
description: Mój przycisk do papieru
photo_4:
id: 4
filename: cat.jpg
thumbnail: cat_t.jpg
description: Moje zwierz
îtko
photo_5:
id: 5
filename: cappucino.jpg
thumbnail: cappucino_t.jpg
description:
Šyciodajny pĪyn
photo_6:
id: 6
filename: building.jpg
thumbnail: building_t.jpg
description: Moje biuro
photo_7:
id: 7
filename: bridge.jpg
thumbnail: bridge_t.jpg
description: Miejsce, które lubi
Ă odwiedzað
photo_8:
id: 8
filename: bear.jpg
thumbnail: bear_t.jpg
description: Dzie
Ĭ w zoo
photo_9:
id: 9
filename: baskets.jpg
thumbnail: baskets_t.jpg
description: Tu przechowuj
Ă owoce
Dane testowe moĔna definiowaè z uĔyciem jözyka YAML. NaleĔy jednak zachowaè ostroĔ-
noĈè, poniewaĔ YAML jest wraĔliwy na wielkoĈè liter. Wprowadzone tak dane testowe moĔ-
na zaäadowaè za pomocñ prostego polecenia
rake
o nazwie
db:fixtures:load
. Wykonajmy
je teraz:
$ rake db:fixtures:load
(in /Users/lance/Projects/book/repo/current/src/chapter2/photos)
W czasie rozwoju aplikacji moĔe siö okazaè w pewnym momencie, Ĕe najlepiej utworzyè bazö
od poczñtku, usuwajñc wszystkie jej tabele, wykonujñc wszystkie migracje i äadujñc ponow-
nie dane testowe. MoĔe siö to zdarzyè, jeĔeli z powodu wystñpienia bäödu migracja uda siö
czöĈciowo. W takim przypadku migracja wstecz moĔe siö nie udaè, poniewaĔ bödzie próbo-
waäa usunñè nieistniejñcñ tabelö. Nie moĔna równieĔ kontynuowaè, poniewaĔ jedna z tabel
nie istnieje — konieczne moĔe siö okazaè röczne poprawianie bazy danych. Istnieje lepsze
rozwiñzanie. MoĔna zbudowaè zadanie
rake
do wyczyszczenia bazy danych, uruchomienia
wszystkich migracji od poczñtku, a nastöpnie zaäadowania danych testowych. Zadania
rake
znajdujñ siö w katalogu lib/tasks. Utwórzmy plik o nazwie lib/tasks/photos.rake, który wyglñda
nastöpujñco:
32
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
namespace :photos do
desc "Ponowne zainicjowanie
Łrodowiska aplikacji"
task :reset => :environment do
Rake::Task["db:migrate:reset"].invoke
Rake::Task["db:fixtures:load"].invoke
end
end
W ten sposób zbudowaliĈmy wäasne zadanie
rake
o nazwie
reset
w przestrzeni nazw
photos
.
Przestrzeþ nazw jest po prostu sposobem organizowania zadaþ
rake
. To nowe zadanie moĔ-
na uruchomiè za pomocñ polecenia
rake photos:reset
.
$ rake photos:reset
(in /Users/lance/Projects/book/repo/current/src/chapter2/photos)
== 20080427170510 CreatePhotos: migrating =====================================
-- create_table(:photos)
-> 0.0036s
== 20080427170510 CreatePhotos: migrated (0.0038s) ============================
W zaleĔnoĈci od platformy moĔna otrzymaè ostrzeĔenie o istniejñcej bazie danych. W takim
przypadku naleĔy je zignorowaè. Zadanie wykonuje dwa inne zadania
rake
:
db:migrate:reset
(usuniöcie wszystkich tabel bazy danych i usuniöcie wierszy z
schema_migrations
) oraz
db:fixtures:load
. Zadania te zaleĔñ od innego zadania
rake
, o nazwie
environment
, które
äaduje odpowiednie Ĉrodowisko. W naszym przypadku Ĉrodowiskiem tym bödzie najczöĈciej
Ĉrodowisko programistyczne.
To wszystko, czego potrzebujemy do zbudowania dziaäajñcego rusztowania aplikacji obsäugi
zdjöè. ćrodowisko Rails wykonaäo resztö pracy. Teraz moĔna otworzyè w przeglñdarce URL
http://localhost:3000/photos i zobaczyè rusztowanie w dziaäaniu. Zobaczymy listö zdjöè z äñcza-
mi do tworzenia nowych zdjöè oraz edycji i wyĈwietlania istniejñcych. Wszystkie strony po-
kazane na rysunku 2.1 zostaäy wykonane za pomocñ generatora szablonów. Generator ten
tworzy zaskakujñco kompletny kod kontrolera i widoku. Trzeba pamiötaè, Ĕe rusztowania
nie zawierajñ kodu gotowego do produkcji, ale sñ tylko punktem startowym. W nastöpnym
punkcie przedstawimy tworzenie rusztowania dla slajdów i zagäöbimy siö nieco w zagadnienia
REST i ĈcieĔek. Ruszajmy!
JeĔeli podczas próby dostöpu do aplikacji otrzymamy nastöpujñcy bäñd:
Mysql::Error in Photo#list
Access denied for user: 'root@localhost' (Using password: NO)
oznacza to, Ĕe po skonfigurowaniu bazy danych nie zostaä uruchomiony ponownie
serwer.
Ļcieżki zgodne z REST
Gdy mamy juĔ dziaäajñce rusztowanie dla zdjöè, moĔemy zajñè siö slajdami. W tym punkcie
utworzymy inne domyĈlne rusztowanie, ale skupimy siö na kontrolerach i ĈcieĔkach, które sñ
wykorzystywane przez Rails przy dostöpie do kaĔdego zasobu. Jak pamiötamy, ĈcieĔka wska-
zuje Rails sposób interpretacji przychodzñcego Ĕñdania URL. Na podstawie URL i ĈcieĔki Rails
moĔe okreĈliè:
x
parametry, jakie Rails przekazuje do kontrolera za pomocñ tablicy
params
,
x
kontroler, do jakiego bödzie siö odwoäywaè Rails (przechowywany
w
params[:controller]
),
x
akcjö wywoäywanñ przez Rails (przechowywana w
params[:action]
).
Ļcieżki zgodne z REST
_
33
PokaĔemy teraz, jak dziaäa REST i ĈcieĔki. Na poczñtek generujemy rusztowanie dla slajdu:
$ script/generate scaffold slide position:integer photo_id:integer slideshow_id:integer
...
create app/views/slides
create app/views/slides/index.html.erb
create app/views/slides/show.html.erb
create app/views/slides/new.html.erb
create app/views/slides/edit.html.erb
create app/views/layouts/slides.html.erb
...
create app/controllers/slides_controller.rb
create test/functional/slides_controller_test.rb
...
route map.resources :slides
...
Jak juĔ wiemy z poprzedniego punktu, Rails utworzy dla nas sporo plików. Tym razem sku-
pimy siö na kontrolerach, widokach i ĈcieĔkach. Tak jak poprzednio, niewielka iloĈè danych
testowych uäatwia testowanie aplikacji. Tym razem skorzystamy z funkcji szablonów. ERb
w Ruby interpretuje pliki osprzötu tak, jakby byäy widokami. Do pliku test/fixtures/slides.yml
wprowadzamy nastöpujñcy kod:
<% 1.upto(9) do |i| %>
slide_<%= i %>:
id: <%= i %>
position: <%= i %>
photo_id: <%= i %>
slideshow_id: 1
<% end %>
W przypadku, gdy ERb znajdzie kod umieszczony pomiödzy
<%
a
%>
, uruchomi go i nic nie
wstawi w to miejsce. JeĔeli jednak ERb znajdzie kod umieszczony pomiödzy
<%=
a
%>
, uru-
chomi go i zastñpi ten kod wartoĈciñ zwróconñ przez operacjö. Ten osprzöt jest odpowiedni-
kiem nastöpujñcych statycznych instrukcji:
slide_1:
id: 1
position: 1
photo_id: 1
slideshow_id: 1
slide_2:
id: 2
position: 2
photo_id: 2
slideshow_id: 1
... i tak dalej ...
W celu zaäadowania naszych danych naleĔy wykonaè polecenie
rake photos:reset
. Po tej
operacji mamy dziaäajñcy zasób dla slajdów wypeäniony przykäadowymi danymi, który ma
taki sam zbiór stron jak rusztowanie dla zdjöè. Przyjrzyjmy siö teraz dziaäaniu ĈcieĔek. Wyge-
nerowane wäaĈnie rusztowanie wykorzystamy w dalszej czöĈci rozdziaäu, ale teraz zajmiemy
siö podstawami ĈcieĔek nazwanych.
Ļcieżki nazwane
Skupmy teraz naszñ uwagö na ĈcieĔkach nazwanych. Wygenerujmy teraz inne rusztowanie,
tym razem dla pokazów slajdów. Wpiszmy:
... script/generate scaffold slideshow
name:string
.
34
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
exists app/models/
exists app/controllers/
exists app/helpers/
...
route map.resources :slideshows
...
Jak zawsze, w celu utworzenia tabel w naszej bazie danych uruchamiamy
rake db:migrate
.
Zwróèmy uwagö na polecenie
route
. Polecenie to tworzy specyficzny wzorzec URL uĔywa-
ny przez aplikacjö. WyjaĈnienie tej operacji zajmie tylko chwilö.
KaĔde polecenie Rails jest odwzorowywane na jednñ ze ĈcieĔek wymienionych w pliku config/
routes.rb. W rozdziale 1., choè tego nie wyjaĈnialiĈmy, Rails wygenerowaä ĈcieĔkö, która wy-
glñdaäa podobnie do
map.connect ':controller/:action/:id'
. Za kaĔdym razem, gdy
Rails napotyka URL w postaci
/kontroler/akcja/identyfikator
, przeksztaäca go na postaè
tablicy o nazwie
params
zawierajñcej klucze
:controller
,
:action
oraz
:id
z wartoĈciami
pobranymi z adresu URL.
Teraz spójrzmy na instrukcjö
route map.resources :slideshows
w pliku config/routes.rb.
Przy generowaniu rusztowania Rails dodaä do pliku routes.rb jeden wiersz. Otwórzmy ten
plik. Blisko poczñtku pliku moĔna znaleĒè instrukcje:
map.resources :slideshows
map.resources :slides
map.resources :photos
Instrukcja
map.resources :slideshows
faktycznie buduje osiem skomplikowanych ĈcieĔek,
do których moĔna odwoäywaè siö wedäug nazwy. Aby wyĈwietliè wszystkie ĈcieĔki w kolej-
noĈci, w jakiej Rails próbuje je dopasowaè, naleĔy skorzystaè z polecenia
rake routes
. Miö-
dzy innymi moĔna zauwaĔyè ĈcieĔki, jakie Rails dodaä do pokazów slajdów. Sñ to gäówne
ĈcieĔki bez ĈcieĔek formatowanych, bödñcych bliskimi kuzynami ĈcieĔek nazwanych, zamiesz-
czonych poniĔej:
slideshows
GET /slideshows
{:action=>"index", :controller=>"slideshows"}
POST /slideshows
{:action=>"create", :controller=>"slideshows"}
new_slideshow
GET /slideshows/new
{:action=>"new", :controller=>"slideshows"}
edit_slideshow
GET /slideshows/:id/edit
{:action=>"edit", :controller=>"slideshows"}
slideshow
GET /slideshows/:id
{:action=>"show", :controller=>"slideshows"}
PUT /slideshows/:id
{:action=>"update", :controller=>"slideshows"}
DELETE /slideshows/:id
{:action=>"destroy", :controller=>"slideshows"}
Aby w peäni zrozumieè, co siö tu dzieje, musimy odwoäaè siö do budowy protokoäu HTTP.
WiökszoĈè programistów wie, Ĕe protokóä HTTP obsäuguje co najmniej dwa polecenia: GET
Ļcieżki zgodne z REST
_
35
oraz POST. Normalnie, gdy przeglñdarka äaduje URL, korzysta z HTTP GET. Gdy wysyäa za-
wartoĈè formularza, korzysta z HTTP POST. Byè moĔe wiesz, Ĕe HTTP obsäuguje równieĔ co
najmniej dwa inne polecenia: PUT i DELETE, choè wiökszoĈè przeglñdarek ich nie obsäuguje.
Teraz zamieszczona powyĔej lista ma nieco wiökszy sens. Widzimy w niej cztery ĈcieĔki na-
zwane:
slideshows
,
new_slideshow
,
edit_slideshow
oraz
slideshow
. (Faktycznie wynik
dziaäania
rake routes
zawiera osiem ĈcieĔek nazwanych, wraz ze sformatowanymi wersja-
mi wszystkich ĈcieĔek nazwanych. ćcieĔki te pomagajñ przetwarzaè formaty plików takie jak
XML, ale na razie nie majñ nic wspólnego ze ĈcieĔkami nazwanymi). NaleĔy zauwaĔyè, Ĕe
po kaĔdej nazwie znajduje siö Ĕñdanie HTTP skäadajñce siö z polecenia, adresu URL oraz od-
wzorowania wykorzystywanego przez Rails przy tym Ĕñdaniu. Ta zasada pokazuje, Ĕe ĈcieĔ-
ka zale
Ĕy od polecenia HTTP. Na przykäad Ĕñdanie HTTP
GET/slideshows/4
wywoäuje metodö
show w kontrolerze
slideshows
, ale
PUT/slideshows/4
wywoäuje akcjö
update
.
REST
We wczeĈniejszej czöĈci tego rozdziaäu zapowiadaäem krótkie wprowadzenie do REST i teraz
jest dobry moment na powrót do tego tematu. MoĔna uwaĔaè REST za sposób patrzenia na
HTTP jak na kolekcjö zasobów. Spójrzmy na polecenia HTTP jak na internetowñ wersjö ope-
racji CRUD w bazie danych:
x
Create: POST
x
Read: GET
x
Update: PUT
x
Delete: DELETE
Jak moĔna zauwaĔyè, ĈcieĔki Rails doskonale pasujñ do tej koncepcji. Uzbrojeni w predefinio-
wane ĈcieĔki nazwane, moĔemy wykonaè dowolnñ operacjö REST. NajczöĈciej moĔna zgad-
nñè, jakñ akcjö kontrolera wygenerowaä dla nas generator rusztowania. Aby potwierdziè nasze
podejrzenia, otwórzmy plik app/controllers/slides_controller.rb. Nie chcemy zamieszczaè caäego
tego kodu ani próbowaè go objaĈniaè. Na razie spójrzmy na metody obsäugiwane przez kon-
troler i na komentarze towarzyszñce kaĔdej z tych metod.
class SlidesController < ApplicationController
# GET /slides
# GET /slides.xml
def index
...
end
# GET /slides/1
# GET /slides/1.xml
def show
...
end
# GET /slides/new
# GET /slides/new.xml
def new
...
end
# GET /slides/1/edit
def edit
...
end
36
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
# POST /slides
# POST /slides.xml
def create
...
end
# PUT /slides/1
# PUT /slides/1.xml
def update
...
end
# DELETE /slides/1
# DELETE /slides/1.xml
def destroy
...
end
end
Metody te doskonale odpowiadajñ ĈcieĔkom nazwanym utworzonym w routes.rb i wymienio-
nym w
rake routes
. Komentarze säuĔñ po prostu jako przypomnienie o ĈcieĔkach nazwanych.
Wiemy, Ĕe GET dla http://nasza_applikacja/slides/new uruchomi akcjö
new
(jak pamiötamy, me-
toda w kontrolerze implementuje akcjö), a POST dla /slides uruchomi akcjö
create
.
Prosta tabela 2.1 pokazuje odwzorowanie pomiödzy metodami HTTP, akcjami Rails oraz ba-
zñ danych. Gdy nauczymy siö myĈleè o kaĔdej aplikacji internetowej jak o zbiorze zasobów,
aplikacja bödzie dla nas prosta.
Tabela 2.1. Polecenia REST ze skojarzonymi metodami Rails i poleceniami bazy danych
Create
Read
Update
Delete
HTTP
POST
GET
PUT
DELETE
Rails
CREATE
SHOW
UPDATE
DESTROY
Baza danych
INSERT
SELECT
UPDATE
DELETE
Zanim bödziemy mogli kontynuowaè, przedstawimy jeszcze jednñ ideö. W Rails powinniĈmy
traktowaè akcje
edit
i
update
jako parö. Akcja
edit
generuje formularz, który przez uĔytkow-
nika moĔe byè uĔyty do modyfikacji slajdu. Wysäanie formularza wywoäuje akcjö
update
, któ-
ra sprawdza poprawnoĈè transakcji i aktualizuje element w bazie danych. W podobny spo-
sób dziaäajñ metody
new
oraz
create
. W dalszej czöĈci ksiñĔki dokäadniej przedstawimy kod
poszczególnych metod kaĔdego z kontrolerów. Na razie moĔemy uĔyè aplikacji do testowa-
nia w konsoli. Konsola moĔe byè uwaĔana za wiersz polecenia dla aplikacji. Na poczñtek do-
konamy edycji pliku app/controllers/slides_controller.rb i dodamy wiersz
skip_before_filter
:
class SlidesController < ApplicationController
skip_before_filter :verify_authenticity_token
...
Powoduje to wyäñczenie Ĕñdania Ĕetonu weryfikacji, czyli nowej funkcji w Rails, pozwalajñcej
upewniè siö, Ĕe Ĕñdanie pochodzi z naszej aplikacji. Po wykonaniu zamieszczonych poniĔej
poleceþ konsoli wiersz ten naleĔy usunñè. Wykorzystajmy teraz nowo zdobytñ wiedzö na te-
mat REST:
$ script/console
Loading development environment (Rails 2.1.0)
>> app.get "/slides"
=> 200
>> app.request.path_parameters
Ļcieżki zgodne z REST
_
37
=> {"action"=>"index", "controller"=>"slides"}
>> app.get "/slides/1"
=> 200
>> app.request.path_parameters
=> {"action"=>"show", "id"=>"1", "controller"=>"slides"}
>> app.post "/slides", :slide => {:position => 10, :photo_id => 1, :slideshow_id => 1}
=> 302
>> app.request.path_parameters
=> {"action"=>"create", "controller"=>"slides"}
>> app.put "/slides/1", :slide => {:position => 1, :photo_id => 1, :slideshow_id => 2}
=> 302
>> app.request.path_parameters
=> {"action"=>"update", "id"=>"1", "controller"=>"slides"}
>> app.delete "/slides/10"
=> 302
>> app.request.path_parameters
=> {"action"=>"destroy", "id"=>"10", "controller"=>"slides"}
Przy uĔyciu tych technik moĔna sprawdzaè dziaäanie aplikacji w taki sam sposób, jakby byäa
wywoäywana z internetu. Polecenia HTTP moĔna wysyäaè do naszej aplikacji za pomocñ ta-
kich poleceþ jak
app.get
. NaleĔy pamiötaè, Ĕe kod powrotu prawidäowo wykonanego pole-
cenia HTTP to 200, a kod powrotu polecenia przekierowania HTTP wynosi 302. Polecenie
path_parameters
pokazuje aktualne parametry, jakie Rails wysyäa do kontrolera w tablicy
params
. JeĔeli zachodzi taka potrzeba, moĔna równieĔ zobaczyè zawartoĈè
app.response.body
po kaĔdym Ĕñdaniu, która to zmienna bödzie przechowywaäa stronö WWW utworzonñ przez
Rails. Po zakoþczeniu testów w konsoli naleĔy usunñè wywoäanie
skip_before_filter
.
Kod kontrolera
Przypomnijmy, czego siö do tej pory dowiedzieliĈmy. JeĔeli w przeglñdarce wpiszemy adres
URL Rails, nasz serwer WWW, Mongrel, przeĈle nasze Ĕñdanie do Rails. Router Rails znajdzie
ĈcieĔkö odpowiadajñcñ Ĕñdaniu, utworzy tablicö asocjacyjnñ
params
i wywoäa kod kontrolera.
Spójrzmy na kod domyĈlnego kontrolera. Nie poznaliĈmy jeszcze Active Record, ale nie bö-
dzie to przeszkodñ. Przeanalizujemy ten kod na wysokim poziomie, a szczegóäami zajmiemy
siö w rozdziale 3. i 4. Przeanalizujmy teraz kilka kolejnych akcji. Zacznijmy od najprostszej
akcji,
show
, w
app/controllers/slideshows_controller.rb
:
# GET /slideshows/1
# GET /slideshows/1.xml
def show
@slideshow = Slideshow.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @slideshow }
end
end
Komentarze informujñ nas dokäadnie, jak dziaäajñ nazwane ĈcieĔki. ēñdanie
GET
dla
slide-
shows/1
lub
/slideshows/1.xml
wywoäuje tö akcjö kontrolera. Wywoäanie
/slideshows/1.xml
daje w wyniku nastöpujñcñ zawartoĈè tablicy
params
:
params
{
:controller => 'slideshows',
:action => 'show',
:id => '1',
:format => 'xml'
}
38
_
Rozdzia
ĥ 2. Rusztowania, REST i ļcieżki
Gdy pominiemy rozszerzenie .xml lub .html, domyĈlnym formatem bödzie html. Instrukcja
@slideshow = Slideshow.find(params[:id])
jest prosta, nawet gdy nie znamy jeszcze Active
Record. Rails znajduje
Slideshow
z wartoĈciñ
id
mieszczñcñ siö w tablicy
params
. Nastöpny
wiersz kodu jest nieco mniej skomplikowany, poniewaĔ mamy zagnieĔdĔony blok kodu:
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @slideshow }
end
Kod ten w sposób warunkowy wykonuje kod bazujñcy na formacie Ĕñdania. Metoda
respond_to
w sposób warunkowy wykonuje blok kodu obok odpowiedniej instrukcji format. Gdy
params
[:format]
ma wartoĈè
xml
, Rails wykonuje
render :xml => @slideshow
, a gdy
params[:
format]
ma wartoĈè
html
, Rails nic nie wykonuje. NaleĔy pamiötaè, Ĕe gdy akcja nie wywo-
äuje jawnie
render
, Rails po prostu generuje domyĈlny widok. Dlatego uproszczony widok,
który obsäuguje tylko Ĕñdania HTML, wyglñda nastöpujñco:
def show
@slideshow = Slideshow.find(params[:id])
# show.html.erb
end
Akcja kontrolera dla metody
index
dziaäa dokäadnie w taki sposób, ale
index
znajduje wszyst-
kie pokazy slajdów zamiast jednego. Kod metody
destroy
jest nieco inny:
def destroy
@slideshow = Slideshow.find(params[:id])
@slideshow.destroy
respond_to do |format|
format.html { redirect_to(slideshows_url) }
format.xml { head :ok }
end
end
Zamiast generowaè akcjö,
destroy
wykonuje przekierowanie do
slideshows_url
, bödñcego
ĈcieĔkñ nazwanñ dla akcji
index
.
Dwie pozostaäe akcje sñ niezwykle proste. Generujñ one formularze do tworzenia i aktualiza-
cji pokazów slajdów. Sñ to akcje
new
oraz
edit
:
# GET /slideshows/new
# GET /slideshows/new.xml
def new
@slideshow = Slideshow.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @slideshow }
end
end
# GET /slideshows/1/edit
def edit
@slideshow = Slideshow.find(params[:id])
end
Metoda
edit
szuka istniejñcych pokazów slajdów i generuje formularz. Metoda
new
tworzy
pusty obiekt i generuje formularz lub kod XML dla pustego elementu. W praktyce rzadko
wywoäujemy metodö
new
dla formatu
xml
. Wysäanie formularza
edit
dla obiektu
Slideshow
z identyfikatorem 1 powoduje wywoäanie Ĕñdania HTTP
PUT slideshows/1
, wywoäanie ak-
cji
update
i przekazanie nowych atrybutów w tablicy
params
dla obiektu
Slideshow
: