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