Foto af Daniele Levis Pelusi på Unsplash
Singulære ressourceruter
Det er også muligt at have ruter for singulære ressourcer, dvs. ressourcer, der kan slås op uden at angive en :id
, som f.eks. dem, der gælder for en current_user
eller current_account
. Dette kan opnås ved at bruge Rails’ indbyggede singulære ressourcer.
resource :profile
Nested Routes
I nogle tilfælde har vi brug for at indlejre ressourcer inde i andre ressourcer. Hvis jeg f.eks. ønsker at oprette en booking for en bestemt bil i min garage, kan det være mere praktisk at hente :id
for den pågældende bil fra URL’en i stedet for et skjult felt i en formular, som en ondsindet bruger kan manipulere med. Måden vi opretter indlejrede ressourcer i rails på er som følger:
resources :cars do
resources :bookings
end
Dette opretter alle syv CRUD-handlinger for bookinger indlejret i biler. Normalt har du dog ikke brug for alle syv ruter. Og selv når du gør det, behøver de bestemt ikke alle sammen at være nested. Lad os sige, at det, vi har brug for, er handlingen til at oprette en booking (vi antager, at formularen til at oprette en booking findes i bilens show-handling) og til at redigere og opdatere en eksisterende booking. Skal jeg kende :id
af en bil for at redigere/opdatere en booking? Svaret er naturligvis nej. Derfor ønsker jeg, at min applikation skal svare på følgende URL’er:
# 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/
som genereres af følgende kode:
resources :cars do
resources :bookings, only:
end
resources :bookings, only:
Rails lader os ændre, hvilke af standard CRUD-ruterne der skal genereres, ved at levere et array af symboler eller et enkelt symbol til indstillingen :only
eller dens modsætning :except
.
Non-CRUD-routere
Vi er ikke begrænset til de syv CRUD-ressourceruter. Vi kan også angive ruter, der gælder for en enkelt ressource (member routes) eller for flere ressourcer (collection routes).
Member routes
Fortsætter vi med vores RubyGarage-eksempel, kan biler parkeres i eller fjernes fra garagen. Lad os forestille os, at vi har controllerhandlinger, der kan udføre disse handlinger, som ændrer en attribut for en bestemt bil.
resources :cars do
member do
patch :park
patch :remove
end
end
Overstående giver os mulighed for at sende patchforespørgsler til http://my-ruby-garage.com/cars/:id/park
og http://my-ruby-garage.com/cars/:id/remove
og finde den specifikke bil i controlleren, før vi ændrer ressourcen i overensstemmelse hermed.
Collection routes
På samme måde ønsker vi nogle gange at udføre en handling på flere ressourcer på samme tid. For eksempel har vi måske brug for at parkere og fjerne en samling biler på én gang. Vi kan bruge følgende kode:
resources :cars do
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end
Her konfigurerer vi vores program til at reagere på http://my-ruby-garage.com/cars/park
og http://my-ruby-garage.com/cars/remove
og navngiver disse handlinger henholdsvis bulk_park og bulk_remove. Husk, at vi kan bruge navngivne stier til at generere URL-stierne inde i vores program. For at opbygge et stiforbindelse til at parkere en samling biler kunne vi bruge:
<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>
Namespaced Routes
Namespaced routes giver URL-stien til ressourcerne inden for namespace-blokken et præfiks og vil forsøge at finde de relevante controllere under et modul med samme navn som namespace. Typiske anvendelser af dette mønster er admin-namespaces og api-namespaces.
namespace :factory do
resources :cars
end
Dette eksempel opbygger følgende ruter:
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
Og controlleren skulle også være namespaced :
class Factory::CarsController < ApplicationController
# ...
end
Scoped Routes
Med scope
-metoden kan vi forblive DRY og bundle relaterede routingregler sammen. Når den bruges uden indstillinger, ligner den namespace
, men de relevante controllere behøver ikke at være namespaced med et modul.
scope :factory do
resources :cars
end
Genererer følgende ruter:
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 understøtter tre indstillinger: module, path og as.
Lad os sige, at vi har en guiden i flere trin for at oprette en ny bil i fabrikken, som håndteres af en controller, der bor i et guidenmodul. Vi ønsker, at stien skal vises i browseren som http://my-ruby-garage.com/create-a-car
og at vi skal kunne henvise til denne rute inde i vores program som create_car
. Der findes et modul Wizard::Car
, som kender hvert trin i guiden.
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
Overstående kode skaber det samme mønster for hvert trin. F.eks. er trin 1 tilgængeligt i browseren via URL http://my-ruby-garage.com/create-a-car/step1
, den tilsvarende formular sender en postanmodning til http://my-ruby-garage.com/create-a-car/validate-step
, og stien kan tilkaldes ved at kalde create_car_step1_path
.
Route omdirigeringer
Rails giver os også mulighed for at lave omdirigeringer direkte i routes.rb
. I det foregående eksempel ønsker jeg måske, at alle, der lander på http://my-ruby-garage.com/create-a-car
, automatisk skal omdirigeres til det første trin. Dette kan opnås med følgende kode:
get 'create-a-car',
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")
Route Defaults
Du kan definere standardparametre i en rute ved at overgive en hash for :defaults
-indstillingen.
resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end
Ved brug af dette vil et besøg på http://my-ruby-garage.com/cars/export
kalde eksporthandlingen i bilernes controller, og den tilsvarende controllerhandling vil som standard svare med en csv.
Route Globbing
Ved hjælp af wildcard-segmenter (fragmenter med en stjerne som præfiks) kan vi angive, at de resterende dele af en rute skal matches med en bestemt parameter. Dette kaldes route globbing.
get '/rent/*slugs', to: 'cars#index', as: :rent_cars
Denne rute ville matche http://my-ruby-garage.com/rent/lisbon/suv-sedan
og indstille params til “lisbon/suv-sedan”. Dette kunne derefter bruges i et opslags- eller filtreringssystem mod vores database for at finde biler i Lissabon af typen suv eller sedan.
Jeg er ved at skrive en gem Slugcatcher med denne funktionalitet i tankerne for at mærke Rails-modeller, der kan slås op som rute-slugs.