Rails 5 Routing Cookbook: 10 przepisów dla początkującego programisty Rails i nie tylko

Należy pamiętać, że Rails jest opiniotwórczym frameworkiem, a jedną z jego podstawowych zasad jest przewaga konwencji nad konfiguracją. Oznacza to, że o ile nie masz bardzo dobrego powodu, nie powinieneś łamać żadnego z powyższych wzorców i konwencji nazewnictwa.

Na przykład, jeśli zdecydowałbym się zakodować akcję index jako get 'cars/index' lub akcję create jako post 'car/create', złamałoby to zachowanie out-of-the-box Rails dla metod pomocniczych takich jak form_for, link_to, i redirect_to.

Konsekwencją łamania konwencji bez zamiaru jest chaos i produkuje on splątany bałagan, który sprawi, że będziesz walczył z frameworkiem przez wiele godzin.

Photo by Daniele Levis Pelusi on Unsplash

Singular Resource Routes

Możliwe jest również posiadanie tras dla pojedynczych zasobów, czyli zasobów, które mogą być wyszukane bez podawania :id, takich jak te odnoszące się do current_user lub current_account. Można to osiągnąć za pomocą wbudowanych w Railsy zasobów singularnych.

resource :profile 

Ruty zagnieżdżone

Czasami potrzebujemy zagnieżdżać zasoby wewnątrz innych zasobów. Na przykład, jeśli chcę utworzyć rezerwację dla konkretnego samochodu w moim garażu, wygodniej jest pobrać :id dla tego samochodu z adresu URL, niż z ukrytego pola formularza, które mogłoby zostać zmanipulowane przez złośliwego użytkownika. Sposób w jaki tworzymy zagnieżdżone zasoby w rails jest następujący:

resources :cars do 
resources :bookings
end

To tworzy wszystkie siedem akcji CRUD dla rezerwacji zagnieżdżonych w samochodach. Zazwyczaj jednak nie potrzebujesz wszystkich siedmiu tras. A nawet jeśli tak jest, z pewnością nie wszystkie z nich muszą być zagnieżdżone. Załóżmy, że potrzebujemy akcji do tworzenia rezerwacji (zakładamy, że formularz do tworzenia rezerwacji znajduje się w akcji pokaż samochód) oraz do edycji i aktualizacji istniejącej rezerwacji. Czy muszę znać :id samochodu, aby edytować/aktualizować rezerwację? Odpowiedź brzmi oczywiście nie. Dlatego chcę, aby moja aplikacja odpowiadała na następujące adresy 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/

, które są generowane przez następujący kod:

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

Rails pozwala nam modyfikować, które ze standardowych tras CRUD powinny być generowane przez dostarczenie tablicy symboli lub pojedynczego symbolu do opcji :only lub jej przeciwieństwa :except.

Trasy nie-CRUD

Nie jesteśmy ograniczeni do siedmiu tras zasobów CRUD. Możemy również określić trasy, które odnoszą się do pojedynczego zasobu (member routes) lub do kilku zasobów (collection routes).

Member routes

Kontynuując nasz przykład RubyGarage, samochody mogą być parkowane w garażu lub z niego usuwane. Wyobraźmy sobie, że mamy akcje kontrolera, które są w stanie wykonać te akcje, które modyfikują jakiś atrybut konkretnego samochodu.

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

Powyższe pozwala nam wysłać żądania poprawek do http://my-ruby-garage.com/cars/:id/park i http://my-ruby-garage.com/cars/:id/remove i znaleźć konkretny samochód w kontrolerze przed odpowiednią modyfikacją zasobu.

Collection routes

W ten sam sposób, czasami chcemy wykonać jakąś akcję na kilku zasobach w tym samym czasie. Na przykład, może potrzebujemy zaparkować i usunąć kolekcję samochodów na raz. Możemy użyć następującego kodu:

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

Tutaj ustawiamy naszą aplikację tak, aby reagowała na http://my-ruby-garage.com/cars/park i http://my-ruby-garage.com/cars/remove i odpowiednio nazywamy te akcje bulk_park i bulk_remove. Pamiętaj, że możemy użyć nazwanych ścieżek do wygenerowania ścieżek URL wewnątrz naszej aplikacji. Aby zbudować link ścieżki do parkowania kolekcji samochodów, moglibyśmy użyć:

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

Namespaced Routes

Namespaced routes poprzedzają ścieżkę URL zasobów wewnątrz bloku przestrzeni nazw i spróbują zlokalizować odpowiednie kontrolery w module o tej samej nazwie co przestrzeń nazw. Typowe zastosowania dla tego wzorca to przestrzenie nazw adminów i przestrzenie nazw api.

namespace :factory do 
resources :cars
end

Ten przykład buduje następujące trasy:

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

A kontroler też musiałby być nazwany :

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

Scoped Routes

Metoda scope pozwala nam zachować DRY i połączyć razem powiązane reguły routingu. Gdy jest używana bez opcji, jest podobna do namespace, ale odpowiednie kontrolery nie muszą być nazwane modułem.

scope :factory do 
resources :cars
end

Generuje następujące trasy:

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 obsługuje trzy opcje: moduł, ścieżka i as.

Powiedzmy, że mamy wieloetapowy kreator do tworzenia nowego samochodu w fabryce, który jest obsługiwany przez kontroler żyjący w module wizards. Chcemy, aby ścieżka pojawiała się w przeglądarce jako http://my-ruby-garage.com/create-a-car i abyśmy mogli odwoływać się do tej trasy wewnątrz naszej aplikacji jako create_car. Istnieje moduł Wizard::Car, który zna każdy krok kreatora.

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

Powyższy kod tworzy ten sam wzorzec dla każdego kroku. Na przykład, krok 1 jest dostępny w przeglądarce przez URL http://my-ruby-garage.com/create-a-car/step1, odpowiadający mu formularz wysyła żądanie post do http://my-ruby-garage.com/create-a-car/validate-step, a ścieżka może być przywołana przez wywołanie create_car_step1_path.

Route Redirects

Railsy pozwalają nam również robić przekierowania bezpośrednio w routes.rb. W poprzednim przykładzie, być może chcę, aby każdy kto wyląduje na http://my-ruby-garage.com/create-a-car został automatycznie przekierowany do pierwszego kroku. Można to osiągnąć za pomocą następującego kodu:

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

Route Defaults

Możesz zdefiniować domyślne parametry w trasie, przekazując hash dla opcji :defaults.

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

Używając tego, odwiedzenie http://my-ruby-garage.com/cars/export wywoła akcję eksportu w kontrolerze samochodów, a odpowiednia akcja kontrolera odpowie domyślnie z csv.

Route Globbing

Używając segmentów wieloznacznych (fragmentów poprzedzonych gwiazdką), możemy określić, że pozostałe części trasy powinny być dopasowane do konkretnego parametru. Nazywa się to globalizacją trasy.

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

Ta trasa dopasowałaby http://my-ruby-garage.com/rent/lisbon/suv-sedan i ustawiła parametry na „lisbon/suv-sedan”. Mogłoby to być użyte w systemie wyszukiwania lub filtrowania w naszej bazie danych w celu znalezienia samochodów w Lizbonie typu suv lub sedan.

Piszę gem Slugcatcher z tą funkcjonalnością w celu oznaczenia modeli Rails, które mogą być wyszukiwane jako route slugs.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.