Rails 5 Routing Cookbook: 10 Rezepte für den Rails-Neuling und darüber hinaus

Sie sollten bedenken, dass Rails ein eigenwilliges Framework ist und eines seiner grundlegenden Prinzipien Konvention vor Konfiguration lautet. Das bedeutet, dass Sie die oben genannten Muster und Namenskonventionen nicht brechen sollten, es sei denn, Sie haben einen sehr guten Grund dafür.

Wenn ich zum Beispiel beschließe, die index-Aktion als get 'cars/index' oder die create-Aktion als post 'car/create' zu kodieren, würde dies das Out-of-the-Box-Verhalten von Rails für Hilfsmethoden wie form_for, link_to und redirect_to brechen.

Die Konsequenz des ungewollten Bruchs von Konventionen ist Chaos und führt zu einem Wirrwarr, das einen stundenlang gegen das Framework ankämpfen lässt.

Foto von Daniele Levis Pelusi auf Unsplash

Routen für einzelne Ressourcen

Es ist auch möglich, Routen für einzelne Ressourcen zu haben, d.h. Ressourcen, die ohne die Angabe eines :id nachgeschlagen werden können, wie z.B. die, die für ein current_user oder current_account gelten. Dies kann durch die Verwendung der in Rails eingebauten singulären Ressourcen erreicht werden.

resource :profile 

Geschachtelte Routen

Gelegentlich müssen wir Ressourcen innerhalb anderer Ressourcen verschachteln. Wenn ich zum Beispiel eine Buchung für ein bestimmtes Auto in meiner Garage erstellen möchte, ist es vielleicht bequemer, das :id für dieses Auto aus der URL zu holen, als ein verstecktes Feld im Formular, das von einem böswilligen Benutzer manipuliert werden könnte. In Rails werden verschachtelte Ressourcen wie folgt erstellt:

resources :cars do 
resources :bookings
end

Damit werden alle sieben CRUD-Aktionen für in Autos verschachtelte Buchungen erstellt. Normalerweise braucht man aber nicht alle sieben Routen. Und selbst wenn, müssen sicherlich nicht alle verschachtelt werden. Nehmen wir an, wir benötigen die Aktion zum Anlegen einer Buchung (wir nehmen an, dass das Formular zum Anlegen einer Buchung in der Show-Aktion des Fahrzeugs enthalten ist) und zum Bearbeiten und Aktualisieren einer bestehenden Buchung. Muss ich die :id eines Fahrzeugs kennen, um eine Buchung zu bearbeiten/zu aktualisieren? Die Antwort ist offensichtlich nein. Daher möchte ich, dass meine Anwendung auf die folgenden URLs reagiert:

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

Die durch den folgenden Code erzeugt werden:

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

Rails lässt uns ändern, welche der Standard-CRUD-Routen erzeugt werden sollen, indem wir ein Array von Symbolen oder ein einzelnes Symbol an die Option :only oder ihr Gegenteil :except übergeben.

Nicht-CRUD-Routen

Wir sind nicht auf die sieben CRUD-Ressourcenrouten beschränkt. Wir können auch Routen angeben, die sich auf eine einzelne Ressource (Member-Routen) oder auf mehrere Ressourcen (Collection-Routen) beziehen.

Member-Routen

Wenn wir mit unserem RubyGarage-Beispiel weitermachen, können Autos in der Garage geparkt oder aus der Garage entfernt werden. Stellen wir uns vor, dass wir Controller-Aktionen haben, die in der Lage sind, diese Aktionen auszuführen, die einige Attribute eines bestimmten Autos ändern.

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

Damit können wir Patch-Anfragen an http://my-ruby-garage.com/cars/:id/park und http://my-ruby-garage.com/cars/:id/remove senden und das bestimmte Auto im Controller finden, bevor wir die Ressource entsprechend ändern.

Sammelrouten

Auf die gleiche Weise wollen wir manchmal eine Aktion auf mehreren Ressourcen gleichzeitig ausführen. Zum Beispiel müssen wir vielleicht eine Sammlung von Autos auf einmal parken und entfernen. Wir können den folgenden Code verwenden:

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

Hier richten wir unsere Anwendung so ein, dass sie auf http://my-ruby-garage.com/cars/park und http://my-ruby-garage.com/cars/remove reagiert und diese Aktionen bulk_park bzw. bulk_remove nennt. Denken Sie daran, dass wir benannte Pfade verwenden können, um die URL-Pfade innerhalb unserer Anwendung zu erzeugen. Um eine Pfadverknüpfung zum Parken einer Sammlung von Autos zu erstellen, könnten wir verwenden:

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

Namespaced Routes

Namespaced Routes stellen den URL-Pfad der Ressourcen innerhalb des Namespace-Blocks voran und versuchen, die entsprechenden Controller unter einem Modul mit demselben Namen wie der Namespace zu finden. Typische Anwendungen für dieses Muster sind Admin-Namespaces und Api-Namespaces.

namespace :factory do 
resources :cars
end

Dieses Beispiel erstellt die folgenden Routen:

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

Und der Controller müsste ebenfalls einen Namespace haben:

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

Scoped Routes

Die scope-Methode ermöglicht es uns, DRY zu bleiben und verwandte Routing-Regeln zu bündeln. Wenn sie ohne Optionen verwendet wird, ist sie ähnlich wie namespace, aber die relevanten Controller müssen nicht mit einem Modul benannt werden.

scope :factory do 
resources :cars
end

Erzeugt die folgenden Routen:

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 unterstützt drei Optionen: module, path und as.

Angenommen, wir haben einen mehrstufigen Assistenten, um ein neues Auto in der Fabrik zu erstellen, der von einem Controller in einem Assistentenmodul verarbeitet wird. Wir möchten, dass der Pfad im Browser als http://my-ruby-garage.com/create-a-car erscheint und dass wir innerhalb unserer Anwendung auf diese Route als create_car verweisen können. Es gibt ein Modul Wizard::Car, das jeden Schritt des Assistenten kennt.

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

Der obige Code erzeugt das gleiche Muster für jeden Schritt. Zum Beispiel ist Schritt1 im Browser über die URL http://my-ruby-garage.com/create-a-car/step1 zugänglich, das zugehörige Formular sendet eine Post-Anfrage an http://my-ruby-garage.com/create-a-car/validate-step, und der Pfad kann durch den Aufruf von create_car_step1_path aufgerufen werden.

Route Redirects

Rails erlaubt uns auch Redirects direkt in routes.rb. Im vorangegangenen Beispiel möchte ich vielleicht, dass jeder, der auf http://my-ruby-garage.com/create-a-car landet, automatisch zum ersten Schritt weitergeleitet wird. Dies kann mit folgendem Code erreicht werden:

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

Route Defaults

Sie können Standardparameter in einer Route definieren, indem Sie einen Hash für die Option :defaults übergeben.

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

Damit wird beim Besuch von http://my-ruby-garage.com/cars/export die Export-Aktion im Autos-Controller aufgerufen und die entsprechende Controller-Aktion wird standardmäßig mit einer csv antworten.

Route Globbing

Mit Hilfe von Wildcard-Segmenten (Fragmente mit einem vorangestellten Stern) können wir festlegen, dass die verbleibenden Teile einer Route mit einem bestimmten Parameter abgeglichen werden sollen. Dies wird als „route globbing“ bezeichnet.

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

Diese Route würde http://my-ruby-garage.com/rent/lisbon/suv-sedan entsprechen und params auf „lisbon/suv-sedan“ setzen. Dies könnte dann in einem Nachschlage- oder Filtersystem gegen unsere Datenbank verwendet werden, um Autos in Lissabon vom Typ SUV oder Sedan zu finden.

Ich schreibe ein Gem Slugcatcher mit dieser Funktionalität im Hinterkopf, um Rails-Modelle zu taggen, die als Routen-Slugs nachgeschlagen werden können.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.