Rails 5 Routing szakácskönyv: 10 recept a kezdő Rails-fejlesztőnek és azon túl

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.

Photo by Daniele Levis Pelusi on Unsplash

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.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.