Měli byste mít na paměti, že Rails je názorově vyhraněný framework a jedním z jeho základních principů je přednost konvencí před konfigurací. To znamená, že pokud k tomu nemáte velmi dobrý důvod, neměli byste porušovat žádný z výše uvedených vzorů a konvencí pojmenování.
Pokud bych se například rozhodl kódovat akci index jako get 'cars/index'
nebo akci create jako post 'car/create'
, porušilo by to out-of-the-box chování Rails pro pomocné metody, jako jsou form_for, link_to a redirect_to.
Důsledkem porušování konvencí bez záměru je chaos a vzniká zamotaný nepořádek, kvůli kterému budete s frameworkem bojovat celé hodiny.
Singulární trasy zdrojů
Možné je také mít trasy pro singulární zdroje, tj. zdroje, které lze vyhledat bez uvedení :id
, například ty, které se vztahují k current_user
nebo current_account
. Toho lze dosáhnout pomocí integrovaných singulárních zdrojů systému Rails.
resource :profile
Vložené trasy
Někdy potřebujeme vnořit zdroje uvnitř jiných zdrojů. Pokud například chci vytvořit rezervaci pro konkrétní auto v garáži, může být výhodnější chytit :id
pro toto auto z adresy URL než ze skrytého pole formuláře, se kterým by mohl zlomyslný uživatel manipulovat. Způsob, jakým vytváříme vnořené prostředky v systému rails, je následující:
resources :cars do
resources :bookings
end
Tím se vytvoří všech sedm akcí CRUD pro rezervace vnořené do aut. Obvykle však všech sedm cest nepotřebujete. A i když je potřebujete, rozhodně nemusí být všechny vnořené. Řekněme, že to, co potřebujeme, je akce pro vytvoření rezervace (budeme předpokládat, že formulář pro vytvoření rezervace sídlí v akci show vozu) a pro úpravu a aktualizaci existující rezervace. Potřebuji k úpravě/aktualizaci rezervace znát :id
vůz? Odpověď je samozřejmě ne. Proto chci, aby moje aplikace reagovala na následující adresy URL:
# to CREATE a booking
POST request to http://my-ruby-garage.com/cars/:id/bookings/create# to EDIT a booking
GET request to http://my-ruby-garage.com/bookings/:id/edit# to UPDATE a booking
PATCH request to http://my-ruby-garage.com/bookings/:id/
Které generuje následující kód:
resources :cars do
resources :bookings, only:
end
resources :bookings, only:
Rails nám umožňuje upravit, která ze standardních tras CRUD má být generována, zadáním pole symbolů nebo jediného symbolu do volby :only
nebo jejího opaku :except
.
Non-CRUD Routes
Nejsme omezeni na sedm tras zdrojů CRUD. Můžeme také zadat trasy, které se vztahují k jednomu prostředku (členské trasy) nebo k několika prostředkům (trasy kolekcí).
Členské trasy
Pokračujeme-li v našem příkladu s garáží RubyGarage, lze do ní zaparkovat auta nebo je z ní vyjmout. Představme si, že máme akce řadiče, které jsou schopny provádět tyto akce, které mění nějaký atribut konkrétního auta.
resources :cars do
member do
patch :park
patch :remove
end
end
Výše uvedené nám umožňuje posílat požadavky na opravu na http://my-ruby-garage.com/cars/:id/park
a http://my-ruby-garage.com/cars/:id/remove
a najít konkrétní auto v řadiči před příslušnou úpravou zdroje.
Sběrné trasy
Stejně tak někdy chceme provést nějakou akci na několika zdrojích najednou. Například možná potřebujeme zaparkovat a odstranit kolekci aut najednou. Můžeme použít následující kód:
resources :cars do
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end
Tady nastavíme naši aplikaci tak, aby reagovala na http://my-ruby-garage.com/cars/park
a http://my-ruby-garage.com/cars/remove
, respektive tyto akce pojmenujeme bulk_park a bulk_remove. Nezapomeňte, že ke generování cest URL uvnitř naší aplikace můžeme použít pojmenované cesty. Pro vytvoření odkazu na cestu k zaparkování sbírky aut bychom mohli použít:
<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>
Jmenné cesty
Jmenné cesty prefixují cestu URL zdrojů uvnitř bloku jmenného prostoru a pokusí se najít příslušné řadiče pod modulem se stejným názvem jako jmenný prostor. Typickým použitím tohoto vzoru jsou jmenné prostory administrátorů a jmenné prostory api.
namespace :factory do
resources :cars
end
Tento příklad vytvoří následující trasy:
Prefix Verb URI Pattern Controller#Action factory_cars GET /factory/cars(.:format) factory/cars#index
POST /factory/cars(.:format) factory/cars#create factory_car GET /factory/cars/:id(.:format) factory/cars#show
PATCH /factory/cars/:id(.:format) factory/cars#update
PUT /factory/cars/:id(.:format) factory/cars#update
DELETE /factory/cars/:id(.:format) factory/cars#destroy
A řadič by musel být také se jmenným prostorem :
class Factory::CarsController < ApplicationController
# ...
end
Scoped Routes
Metoda scope
nám umožňuje zůstat DRY a sdružovat související pravidla směrování. Při použití bez voleb je podobná metodě namespace
, ale příslušné kontroléry nemusí mít jmenný rozsah modulu.
scope :factory do
resources :cars
end
Generuje následující trasy:
Prefix Verb URI Pattern Controller#Action factory_cars GET /factory/cars(.:format) cars#index
POST /factory/cars(.:format) cars#create factory_car GET /factory/cars/:id(.:format) cars#show
PATCH /factory/cars/:id(.:format) cars#update
PUT /factory/cars/:id(.:format) cars#update
DELETE /factory/cars/:id(.:format) cars#destroy
Scope podporuje tři volby: module, path a as.
Řekněme, že máme vícekrokového průvodce vytvořením nového vozu v továrně, který je obsluhován kontrolérem žijícím v modulu průvodce. Chceme, aby se cesta v prohlížeči zobrazovala jako http://my-ruby-garage.com/create-a-car
a aby bylo možné na tuto cestu odkazovat uvnitř naší aplikace jako create_car
. Existuje modul Wizard::Car
, který zná jednotlivé kroky průvodce:
scope module: 'wizards', path: 'create-a-car', as: 'create_car' do
Wizard::Car::STEPS.each do |step|
get step, to: "cars##{step}"
end
post :validate-step, to: 'cars#validate_step'
end
Výše uvedený kód vytvoří pro každý krok stejný vzor. Například krok1 je v prohlížeči dostupný prostřednictvím adresy URL http://my-ruby-garage.com/create-a-car/step1
, jemu odpovídající formulář odešle požadavek na http://my-ruby-garage.com/create-a-car/validate-step
a cestu lze vyvolat voláním create_car_step1_path
.
Přesměrování trasy
Rails nám také umožňuje provádět přesměrování přímo v routes.rb
. V předchozím příkladu třeba chci, aby každý, kdo přistane na http://my-ruby-garage.com/create-a-car
, byl automaticky přesměrován na první krok. Toho lze dosáhnout pomocí následujícího kódu:
get 'create-a-car',
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")
Vypnutelné parametry trasy
Vypnutelné parametry trasy můžete definovat předáním hashe pro volbu :defaults
.
resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end
Pomocí tohoto kódu návštěva http://my-ruby-garage.com/cars/export
zavolá akci exportu v kontroléru cars a odpovídající akce kontroléru bude ve výchozím nastavení odpovídat pomocí csv.
Route Globbing
Pomocí segmentů se zástupnými znaky (fragmenty s předponou hvězdička) můžeme určit, že zbývající části trasy mají odpovídat určitému parametru. Tomuto postupu se říká route globbing.
get '/rent/*slugs', to: 'cars#index', as: :rent_cars
Tato trasa by odpovídala http://my-ruby-garage.com/rent/lisbon/suv-sedan
a nastavila by parametry na „lisbon/suv-sedan“. To by pak mohlo být použito v systému vyhledávání nebo filtrování proti naší databázi k nalezení aut v Lisabonu typu suv nebo sedan.
Píšu gem Slugcatcher s ohledem na tuto funkcionalitu, aby bylo možné označit modely Rails, které lze vyhledat jako route slugs.
.