Rails 5 Routing Cookbook: 10 recept för nybörjare inom Rails och mer än så

Du bör ha i åtanke att Rails är ett ramverk med många åsikter och att en av dess underliggande principer är att konvention är viktigare än konfiguration. Detta innebär att om du inte har en mycket god anledning bör du inte bryta mot något av ovanstående mönster och namnkonventioner.

Om jag till exempel bestämde mig för att koda indexåtgärden som get 'cars/index' eller create-åtgärden som post 'car/create', skulle detta bryta mot Rails out-of-the-box-beteende för hjälpmetoder som form_for, link_to och redirect_to.

Konsekvensen av att bryta mot konventioner utan avsikt är kaos och det ger en trasslig röra som får dig att kämpa mot ramverket i flera timmar.

Foto av Daniele Levis Pelusi på Unsplash

Singulära resurskurser

Det går också att ha rutter för singulära resurser, det vill säga resurser som kan sökas utan att ange en :id, till exempel de som gäller för en current_user eller current_account. Detta kan uppnås genom att använda Rails inbyggda singulära resurser.

resource :profile 

Nested Routes

Ibland måste vi nästla in resurser i andra resurser. Om jag till exempel vill skapa en bokning för en viss bil i mitt garage kan det vara bekvämare att hämta :id för den bilen från URL:en än ett dolt fält i ett formulär, som kan manipuleras av en illasinnad användare. Sättet vi skapar inbäddade resurser i rails är följande:

resources :cars do 
resources :bookings
end

Detta skapar alla sju CRUD-åtgärder för bokningar inbäddade i bilar. Vanligtvis behöver du dock inte alla sju rutter. Och även när du gör det behöver säkert inte alla av dem vara nästlade. Låt oss säga att det vi behöver är åtgärden för att skapa en bokning (vi antar att formuläret för att skapa en bokning finns i bilens show-åtgärd) och för att redigera och uppdatera en befintlig bokning. Måste jag känna till bilens :id för att redigera/uppdatera en bokning? Svaret är naturligtvis nej. Därför vill jag att min applikation ska svara på följande 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/

som genereras av följande kod:

resources :cars do 
resources :bookings, only:
end
resources :bookings, only:

Rails låter oss ändra vilka av CRUD-standardrutterna som ska genereras genom att tillhandahålla en array av symboler eller en enda symbol till alternativet :only eller dess motsats :except.

Non-CRUD Routes

Vi är inte begränsade till de sju CRUD-resursrutterna. Vi kan också ange rutter som gäller en enskild resurs (medlemsrutter) eller flera resurser (samlingsrutter).

Medlemsrutter

Fortsätter vi med vårt RubyGarage-exempel kan bilar parkeras i eller tas bort från garaget. Låt oss föreställa oss att vi har controlleråtgärder som kan utföra dessa åtgärder som ändrar något attribut för en specifik bil.

resources :cars do 
member do
patch :park
patch :remove
end
end

Ovanstående gör det möjligt för oss att skicka patchförfrågningar till http://my-ruby-garage.com/cars/:id/park och http://my-ruby-garage.com/cars/:id/remove och hitta den specifika bilen i controllern innan vi ändrar resursen i enlighet med detta.

Collection routes

På samma sätt vill vi ibland utföra någon åtgärd på flera resurser samtidigt. Till exempel kanske vi behöver parkera och ta bort en samling bilar på en gång. Vi kan använda följande kod:

resources :cars do 
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end

Här ställer vi in vårt program så att det svarar på http://my-ruby-garage.com/cars/park och http://my-ruby-garage.com/cars/remove och ger dessa åtgärder namnen bulk_park respektive bulk_remove. Kom ihåg att vi kan använda namngivna sökvägar för att generera URL-sökvägar i vårt program. För att skapa en sökvägslänk för att parkera en samling bilar kan vi använda:

<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>

Namespaced Routes

Namespaced routes prefixerar URL-sökvägen för resurserna inne i namespace-blocket och kommer att försöka hitta de relevanta styrenheterna under en modul med samma namn som namespace. Typiska användningsområden för det här mönstret är admin namespaces och api namespaces.

namespace :factory do 
resources :cars
end

Det här exemplet bygger följande rutter:

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

Och kontrollern skulle också behöva vara namespaced :

class Factory::CarsController < ApplicationController
# ...
end

Scoped Routes

Med scope-metoden kan vi förbli DRY och bunta ihop relaterade routningsregler. När den används utan alternativ liknar den namespace, men de relevanta styrenheterna behöver inte vara namespaced med en modul.

scope :factory do 
resources :cars
end

Genererar följande rutter:

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 har stöd för tre alternativ: module, path och as.

Säg att vi har en flerstegsguide för att skapa en ny bil i fabriken, som hanteras av en styrenhet som bor i en guidenmodul. Vi vill att sökvägen ska visas i webbläsaren som http://my-ruby-garage.com/create-a-car och att vi ska kunna referera till denna väg i vårt program som create_car. Det finns en modul Wizard::Car som känner till varje steg 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

Ovanstående kod skapar samma mönster för varje steg. Till exempel är steg 1 tillgängligt i webbläsaren via URL http://my-ruby-garage.com/create-a-car/step1, dess motsvarande formulär skickar en postförfrågan till http://my-ruby-garage.com/create-a-car/validate-step och sökvägen kan kallas genom att ringa create_car_step1_path.

Route Redirects

Rails låter oss också göra omdirigeringar direkt i routes.rb. I föregående exempel kanske jag vill att alla som landar på http://my-ruby-garage.com/create-a-car automatiskt ska omdirigeras till det första steget. Detta kan åstadkommas med följande kod:

get 'create-a-car', 
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")

Route Defaults

Du kan definiera standardparametrar i en rutt genom att överlämna en hash för :defaults-alternativet.

resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end

Med hjälp av detta kommer ett besök på http://my-ruby-garage.com/cars/export att anropa exportåtgärden i bilarnas kontrollant och motsvarande kontrollantåtgärd kommer att svara med en csv som standard.

Route Globbing

Med hjälp av wildcard-segment (fragment som föregås av en stjärna) kan vi ange att de återstående delarna av en rutt ska matchas mot en viss parameter. Detta kallas route globbing.

get '/rent/*slugs', to: 'cars#index', as: :rent_cars

Denna rutt skulle matcha http://my-ruby-garage.com/rent/lisbon/suv-sedan och ställa in params till ”lisbon/suv-sedan”. Detta skulle sedan kunna användas i ett uppslags- eller filtersystem mot vår databas för att hitta bilar i Lissabon av typen suv eller sedan.

Jag skriver en gem Slugcatcher med denna funktionalitet i åtanke för att märka Rails-modeller som kan sökas upp som route slugs.

Lämna ett svar

Din e-postadress kommer inte publiceras.