Rails 5 Routing Cookbook: 10 opskrifter til nybegyndere inden for Rails-udvikling og mere

Du skal huske på, at Rails er et meningsfyldt framework, og et af dets underliggende principper er konvention frem for konfiguration. Det betyder, at medmindre du har en meget god grund, bør du ikke bryde nogen af ovenstående mønstre og navngivningskonventioner.

Hvis jeg f.eks. besluttede at kode index-aktionen som get 'cars/index' eller create-aktionen som post 'car/create', ville det bryde den out-of-the-box Rails-adfærd for hjælpe-metoder som form_for, link_to og redirect_to.

Følgen af at bryde konventioner uden hensigt er kaos, og det giver et sammenfiltret rod, som vil få dig til at kæmpe mod rammen i timevis.

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.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.