Rails 5 Routing Kookboek: 10 recepten voor de beginnende Rails ontwikkelaar en verder

Je moet in gedachten houden dat Rails een opiniërend framework is en een van de onderliggende principes is conventie boven configuratie. Dit betekent dat, tenzij je een zeer goede reden hebt, je geen van de bovenstaande patronen en naamgevingsconventies moet doorbreken.

Als ik bijvoorbeeld zou besluiten om de index-actie als get 'cars/index' of de create-actie als post 'car/create' te coderen, zou dit het out-of-the-box Rails-gedrag voor helpermethoden zoals form_for, link_to en redirect_to doorbreken.

Het gevolg van het breken van conventies zonder opzet is chaos en het produceert een warrige puinhoop die je urenlang tegen het raamwerk zal laten vechten.

Photo by Daniele Levis Pelusi on Unsplash

Singular Resource Routes

Het is ook mogelijk om routes voor singuliere bronnen te hebben, dat wil zeggen, bronnen die kunnen worden opgezocht zonder een :id te specificeren, zoals degene die van toepassing zijn op een current_user of current_account. Dit kan worden bereikt door gebruik te maken van Rails’ ingebouwde enkelvoudige resources.

resource :profile 

Nested Routes

Soms moeten we resources in andere resources nesten. Als ik bijvoorbeeld een boeking wil maken voor een specifieke auto in mijn garage, kan het handiger zijn om de :id voor die auto uit de URL te halen in plaats van een verborgen veld in het formulier, waarmee door een kwaadwillende gebruiker geknoeid zou kunnen worden. De manier waarop we geneste bronnen maken in rails is als volgt:

resources :cars do 
resources :bookings
end

Dit creëert alle zeven CRUD acties voor boekingen genest in auto’s. Meestal heb je echter niet alle zeven routes nodig. En zelfs als je ze nodig hebt, hoeven ze zeker niet allemaal genest te zijn. Laten we zeggen dat wat we nodig hebben de actie is om een boeking te maken (we nemen aan dat het formulier om een boeking te maken in de show actie van de auto staat) en om een bestaande boeking te bewerken en bij te werken. Moet ik de :id van een auto kennen om een boeking te kunnen wijzigen/bijwerken? Het antwoord is natuurlijk nee. Daarom wil ik dat mijn applicatie reageert op de volgende URL’s:

# 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/

Wie worden gegenereerd door de volgende code:

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

Rails laat ons wijzigen welke van de standaard CRUD routes moeten worden gegenereerd door het leveren van een array van symbolen of een enkel symbool aan de optie :only of zijn tegengestelde :except.

Non-CRUD Routes

We zijn niet beperkt tot de zeven CRUD resource routes. We kunnen ook routes specificeren die van toepassing zijn op een enkele resource (member routes) of op meerdere resources (collection routes).

Member routes

Doorgaand op ons RubyGarage voorbeeld, auto’s kunnen worden geparkeerd in of verwijderd uit de garage. Laten we ons voorstellen dat we controller-acties hebben die in staat zijn om deze acties uit te voeren die een of ander attribuut van een specifieke auto wijzigen.

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

Het bovenstaande stelt ons in staat om patch-verzoeken naar http://my-ruby-garage.com/cars/:id/park en http://my-ruby-garage.com/cars/:id/remove te sturen en de specifieke auto in de controller te vinden voordat de resource dienovereenkomstig wordt gewijzigd.

Collection routes

Op dezelfde manier willen we soms een of andere actie op meerdere resources tegelijkertijd uitvoeren. Bijvoorbeeld, misschien moeten we een verzameling auto’s in één keer parkeren en verwijderen. We kunnen de volgende code gebruiken:

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

Hier stellen we onze applicatie in om te reageren op http://my-ruby-garage.com/cars/park en http://my-ruby-garage.com/cars/remove en, respectievelijk, deze acties bulk_park en bulk_remove te noemen. Onthoud dat we named paths kunnen gebruiken om de URL paden binnen onze applicatie te genereren. Om een padlink te maken om een verzameling auto’s te parkeren, zouden we kunnen gebruiken:

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

Namespaced Routes

Namespaced routes geven een voorvoegsel aan het URL pad van de bronnen binnen het namespace blok en zullen proberen om de relevante controllers te lokaliseren onder een module met dezelfde naam als de namespace. Typisch gebruik voor dit patroon zijn admin namespaces en api namespaces.

namespace :factory do 
resources :cars
end

Dit voorbeeld bouwt de volgende routes:

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

En de controller zou ook namespaced moeten zijn :

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

Scoped Routes

De scope methode staat ons toe om DRY te blijven en gerelateerde routing regels te bundelen. Wanneer het zonder opties wordt gebruikt, is het vergelijkbaar met namespace, maar de relevante controllers hoeven geen namespaced te zijn met een module.

scope :factory do 
resources :cars
end

Genereert de volgende routes:

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 ondersteunt drie opties: module, pad en als.

Laten we zeggen dat we een multi-step wizard hebben om een nieuwe auto in de fabriek te maken die wordt afgehandeld door een controller die in een wizards module zit. We willen dat het pad in de browser verschijnt als http://my-ruby-garage.com/create-a-car en dat we in onze applicatie naar deze route kunnen verwijzen als create_car. Er is een module Wizard::Car die elke stap van de wizard kent.

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

De bovenstaande code creëert hetzelfde patroon voor elke stap. Bijvoorbeeld, stap1 is toegankelijk in de browser via de URL http://my-ruby-garage.com/create-a-car/step1, het bijbehorende formulier stuurt een post request naar http://my-ruby-garage.com/create-a-car/validate-step, en het pad kan worden opgeroepen door create_car_step1_path aan te roepen.

Route Redirects

Rails laat ons ook direct redirects doen in routes.rb. In het voorgaande voorbeeld, wil ik misschien dat iedereen die landt op http://my-ruby-garage.com/create-a-car automatisch wordt doorgestuurd naar de eerste stap. Dit kan worden bereikt met de volgende code:

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

Route Defaults

U kunt standaard parameters in een route definiëren door een hash voor de :defaults optie door te geven.

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

Door dit te gebruiken, zal een bezoek aan http://my-ruby-garage.com/cars/export de export actie in de auto’s controller aanroepen en de corresponderende controller actie zal standaard reageren met een csv.

Route Globbing

Met behulp van wildcard segmenten (fragmenten voorafgegaan door een ster), kunnen we aangeven dat de resterende delen van een route moeten worden gematched met een bepaalde parameter. Dit heet route globbing.

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

Deze route zou overeenkomen met http://my-ruby-garage.com/rent/lisbon/suv-sedan en de params instellen op “lisbon/suv-sedan”. Dit zou dan gebruikt kunnen worden in een lookup of filter systeem tegen onze database om auto’s te vinden in Lissabon van het type suv of sedan.

Ik ben een gem Slugcatcher aan het schrijven met deze functionaliteit in gedachten om Rails modellen te taggen die opgezocht kunnen worden als route slugs.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.