Nem szabad elfelejtened, hogy a Rails egy véleményvezérelt keretrendszer, és az egyik alapelve a konvenció a konfiguráció helyett. Ez azt jelenti, hogy hacsak nincs nagyon jó okod rá, nem szabad megszegned a fenti minták és elnevezési konvenciók egyikét sem.
Ha például úgy döntenék, hogy az index action-t get 'cars/index'
vagy a create action-t post 'car/create'
-ként kódolnám, akkor ez megszegné a Rails out-of-the-box viselkedését az olyan segédmódszerek esetében, mint a form_for, link_to és redirect_to.
A konvenciók szándék nélküli megszegésének következménye a káosz, és egy olyan kusza zűrzavart eredményez, ami miatt órákig fogsz harcolni a keretrendszerrel.
Singular Resource Routes
Egyedi erőforrásokhoz is lehetnek útvonalak, vagyis olyan erőforrások, amelyek :id
megadása nélkül kereshetők, mint például a current_user
vagy current_account
-re vonatkozók. Ezt a Rails beépített szinguláris erőforrásainak használatával érhetjük el.
resource :profile
Beépített útvonalak
Néha szükségünk van arra, hogy erőforrásokat építsünk be más erőforrásokba. Például, ha a garázsomban lévő egy bizonyos autóra szeretnék foglalást létrehozni, kényelmesebb lehet, ha az URL-ből megragadom az adott autóra vonatkozó :id
adatot, mint egy űrlap rejtett mezőjét, amelyet egy rosszindulatú felhasználó manipulálhat. Az egymásba ágyazott erőforrások létrehozásának módja a railsben a következő:
resources :cars do
resources :bookings
end
Ez mind a hét CRUD műveletet létrehozza az autókba ágyazott foglalásokhoz. Általában azonban nincs szükség mind a hét útvonalra. És ha mégis, akkor sem biztos, hogy mindegyiket be kell fészkelni. Tegyük fel, hogy szükségünk van egy foglalás létrehozására (feltételezzük, hogy a foglalás létrehozására szolgáló űrlap az autó show műveletében található), valamint egy meglévő foglalás szerkesztésére és frissítésére. A foglalás szerkesztéséhez/frissítéséhez ismernem kell az autó :id
-jét? A válasz nyilvánvalóan nem. Ezért azt akarom, hogy az alkalmazásom a következő URL-ekre válaszoljon:
# 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/
Azokat a következő kód generálja:
resources :cars do
resources :bookings, only:
end
resources :bookings, only:
A Rails lehetővé teszi számunkra, hogy módosítsuk, hogy a szabványos CRUD útvonalak közül melyeket generáljuk, ha a :only
vagy annak ellenkezője :except
opcióhoz egy szimbólumtömböt vagy egyetlen szimbólumot adunk meg.
Nem-CRUD útvonalak
Nem vagyunk a hét CRUD erőforrás útvonalra korlátozva. Olyan útvonalakat is megadhatunk, amelyek egyetlen erőforrásra (tag útvonalak) vagy több erőforrásra (gyűjtemény útvonalak) vonatkoznak.
Tag útvonalak
Folytatva a RubyGarage példánkat, az autókat be lehet parkolni a garázsba vagy ki lehet venni onnan. Képzeljük el, hogy vannak olyan vezérlői műveleteink, amelyek képesek végrehajtani ezeket a műveleteket, amelyek egy adott autó valamilyen attribútumát módosítják.
resources :cars do
member do
patch :park
patch :remove
end
end
A fentiek lehetővé teszik számunkra, hogy a http://my-ruby-garage.com/cars/:id/park
és http://my-ruby-garage.com/cars/:id/remove
felé küldjünk javítási kéréseket, és megtaláljuk az adott autót a vezérlőben, mielőtt az erőforrást ennek megfelelően módosítanánk.
Collection routes
Hasonlóképpen, néha szeretnénk egyszerre több erőforráson is végrehajtani valamilyen műveletet. Például lehet, hogy egyszerre kell leparkolnunk és eltávolítanunk egy gyűjteménynyi autót. Használhatjuk a következő kódot:
resources :cars do
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end
Itt beállítjuk az alkalmazásunkat, hogy válaszoljon a http://my-ruby-garage.com/cars/park
és http://my-ruby-garage.com/cars/remove
értékekre, és nevezzük el ezeket a műveleteket bulk_park és bulk_remove. Ne feledjük, hogy az URL-útvonalakat az alkalmazásunkon belüli URL-útvonalak létrehozásához nevesített elérési utakat használhatunk. Az autók gyűjteményének parkolásához szükséges elérési útvonalkapcsolat létrehozásához használhatnánk:
<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>
Namespaced Routes
A névtérblokkon belüli erőforrások URL-útvonalát előtaggal látjuk el, és megpróbálja megtalálni a megfelelő vezérlőket egy olyan modul alatt, amelynek neve megegyezik a névtérrel. Ennek a mintának tipikus felhasználási területei az admin névterek és az api névterek.
namespace :factory do
resources :cars
end
Ez a példa a következő útvonalakat építi fel:
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
És a vezérlőt is névtérbe kellene helyezni :
class Factory::CarsController < ApplicationController
# ...
end
Scoped Routes
A scope
módszer lehetővé teszi, hogy DRY maradjunk és a kapcsolódó útválasztási szabályokat összefogjuk. Opciók nélkül használva hasonló a namespace
-hez, de a vonatkozó vezérlőket nem kell modul névtérrel ellátni.
scope :factory do
resources :cars
end
A következő útvonalakat generálja:
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
A hatókör három opciót támogat: modul, path és as.
Tegyük fel, hogy van egy többlépéses varázslónk egy új autó létrehozására a gyárban, amelyet egy varázsló modulban élő vezérlő kezel. Szeretnénk, ha az útvonal http://my-ruby-garage.com/create-a-car
-ként jelenne meg a böngészőben, és create_car
-ként tudnánk hivatkozni erre az útvonalra az alkalmazásunkon belül. Van egy Wizard::Car
modul, amely ismeri a varázsló minden egyes lépését.
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
A fenti kód minden lépésnél ugyanazt a mintát hozza létre. Például az 1. lépés a böngészőben a http://my-ruby-garage.com/create-a-car/step1
URL-en keresztül érhető el, a hozzá tartozó űrlap egy post kérést küld a http://my-ruby-garage.com/create-a-car/validate-step
-be, az útvonal pedig a create_car_step1_path
meghívásával hívható elő.
Route átirányítások
A Rails lehetővé teszi számunkra az átirányításokat közvetlenül a routes.rb
-ben is. Az előző példában talán azt szeretném, ha bárki, aki a http://my-ruby-garage.com/create-a-car
-re érkezik, automatikusan átirányításra kerülne az első lépésre. Ezt a következő kóddal érhetjük el:
get 'create-a-car',
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")
Route Defaults
Egy útvonalban alapértelmezett paramétereket definiálhatunk egy hash átadásával a :defaults
opcióhoz.
resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end
Ezt használva a http://my-ruby-garage.com/cars/export
meglátogatása meg fogja hívni az autók vezérlőjében az export műveletet, és a megfelelő vezérlő művelet alapértelmezetten egy csv-vel fog válaszolni.
Route Globbing
A wildcard szegmensek (csillaggal előtagolt töredékek) használatával megadhatjuk, hogy az útvonal fennmaradó részei egy adott paraméterhez illeszkedjenek. Ezt nevezzük route globbingnak.
get '/rent/*slugs', to: 'cars#index', as: :rent_cars
Ez az útvonal megfelelne a http://my-ruby-garage.com/rent/lisbon/suv-sedan
-nak, és a params-t a “lisbon/suv-sedan”-ra állítaná. Ezt aztán fel lehetne használni egy kereső vagy szűrő rendszerben az adatbázisunkban, hogy megtaláljuk a suv vagy sedan típusú autókat Lisszabonban.
Egy gem Slugcatcher-t írok ezzel a funkcionalitással a fejemben, hogy Rails modelleket címkézzek, amiket route slugs-ként lehet keresni.