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.
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.