Convenzioni di routing di base
Diamo un’occhiata ai nostri percorsi come sono ora, usando rake routes
:
$ rake routes Prefix Verb URI Pattern Controller#Action list_posts GET /list_posts(.:format) application#list_posts GET /show_post/:id(.:format) application#show_post new_post GET /new_post(.:format) application#new_post create_post POST /create_post(.:format) application#create_post GET /edit_post/:id(.:format) application#edit_post POST /update_post/:id(.:format) application#update_post POST /delete_post/:id(.:format) application#delete_post POST /create_comment_for_post/:post_id(.:format) application#create_comment POST /list_posts/:post_id/delete_comment/:comment_id(.:format) application#delete_comment list_comments GET /list_comments(.:format) application#list_comments
Una delle informazioni chiave per le convenzioni Rails è che le app incentrate sui dati (o le app crudeli) tendono ad avere modi molto simili per consentire agli utenti di interagire con l’applicazione, che sono:
- una pagina per visualizzare un elenco di qualcosa
- cosa vista
- mostra una maschera per creare una nuova istanza di qualcosa
- effettivamente creare qualcosa di
- visualizzare un form per la modifica di un’istanza di qualcosa
- aggiorna effettivamente qualcosa
- elimina qualcosa
Quei sette “modelli di interazione” sono così comuni, che Rails fornisce un insieme di convenzioni per il routing per i controller, idee e forme per contribuire a rendere questi flussi di lavoro più semplice. Ora ci concentreremo sulla parte di routing.
Per il routing, la convenzione è che invece di noi che hanno a venire con il pattern URL, Guide consiglia di struttura gli Url e le corrispondenti azioni di controller nel modo seguente:
Flusso di lavoro | HTTP VERBO | PERCORSO | Controller Azione |
---|---|---|---|
Mostra un elenco dei post | GET | /post | post#indice |
Vedi un post | GET | /posts/:id | post#mostra |
Vedi la pagina per creare post | GET | /posts/nuovo | post#nuovo |
Creare un post | POST | /post | post#creare |
Mostra la pagina di modifica di un post | GET | /posts/:id/modifica | post#modifica |
l’Aggiornamento di un post | PUT/PATCH | /posts/id: | post#aggiornamento |
Eliminare un post | ELIMINA | /posts/:id | post#distruggere |
Siamo in grado di modificare il post
parte della nostra corrente di routing per seguire questa convenzione:
# posts GET /list_posts -> GET /posts posts#index GET /show_post/:id -> GET /posts/:id posts#show GET /new_post -> GET /posts/new posts#new POST /create_post -> POST /posts posts#create GET /edit_post/:id -> GET /posts/:id/edit posts#edit POST /update_post/:id -> PUT/PATCH /posts/:id posts#update POST /delete_post/:id -> DELETE /posts/:id posts#destroy
E nel routes.rb
file,
Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' # comments later.. ... end
si Noti che con questo nuovo modello, ci sono un sacco di meno verbi nell’URL, ma stiamo contando sui verbi HTTP (GET
/POST
/PUT
/PATCH
/DELETE
) per fornire la semantica per il resto schemi di URL, per esempio /posts/:id
.
Si noti che PUT
era stato utilizzato per aggiornare le risorse fino a poco tempo fa, quando PATCH
era determinato per essere una corrispondenza semantica migliore per questa azione. Da allora, Rails è passato a preferire PATCH
, ma consentendo entrambi i verbi per gli aggiornamenti.
Un’altra modifica che vedremo più avanti è che instraderemo tutti gli URL relativi ai post su un PostsController
invece di gestire tutto in ApplicationController
. I nomi delle azioni PostController
- new
- index
- show
- create
- edit
- update
- destroy
sono anche convenzioni corrispondenti all’interazione 7 modelli.
Questo è il più forte insieme di convenzioni che Rails impone a voi come sviluppatore di applicazioni. Ti chiederemo di fare uno sforzo per memorizzarlo. Ci rivisiteremo questo un sacco di volte in tutto il libro per aiutarvi a farlo pure.
Routing per più risorse
Spesso abbiamo bisogno di avere più risorse presenti nell’URL. Ad esempio per la nostra app blog ogni volta che abbiamo bisogno di avere un percorso per creare un commento, è molto importante sapere su quale post viene creato questo commento.
Attualmente lo stiamo facendo:
post 'create_comment_for_post/:post_id' => 'application#create_comment'
La convenzione Rails di un URL con più risorse associate è di iniziare con la risorsa “contenente” fino alla risorsa “più interna”. Ad esempio, i nostri percorsi per i commenti cambierebbero in:
post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' get '/comments' => 'comments#index'
La semantica di tali URL rappresenta: “Crea un commento sotto un post specifico” e “elimina un commento sotto un post specifico”. L’ultimo percorso, “mostra tutti i commenti nel sistema”, non ha bisogno di essere “ambito” sotto un post, quindi l’URL non deve condurre con “/posts”.
Se abbiamo bisogno di avere più risorse nell’URL con i loro ID, la convenzione è tale che l’ultima risorsa utilizzerà il segnaposto :id
e tutto il resto sarà :resource_id
come :post_id
.
Restful
REST sta per “Representational State Transfer”. È uno stile di architettura software e una linea guida per creare servizi Web scalabili. REST, come un modo per strutturare le applicazioni web, ha molte sfaccettature ad esso, ma diamo solo un’occhiata a come si applica all’interfaccia che usiamo per interagire con le applicazioni web, gli URL.
Per vedere come REST semplifica la semantica degli URL, esaminiamo un esempio. Diciamo che stiamo costruendo un servizio di ordinazione di pizza online. Un’implementazione naïve delle interfacce del servizio (URL) sarebbe:
/check_order?order_id=2 /place_new_order /pizza_details?type=1 /pay_for_my_order?order_id=12 /cancel_order?order_id=3 /expedite_order?order_id=13
Un design di interfaccia RESTful sarebbe simile a questo:
GET /orders/2 POST /orders GET /pizzas/1 POST /orders/12/payments DELETE /orders/3 POST /orders/13/expeditions
Puoi vedere, le interfacce RESTful si concentrano su “nomi” o “risorse”, rimuovendo “verbi” dalle interfacce ma basandosi invece sui verbi HTTP standardizzati(GET
/POST
/PUT
/DELETE
) fornire semantica CRUD per le azioni. Verbi come check
, place
, cancel
sono mappati direttamente ai verbi HTTP di GET
per recuperare, POST
per creare e DELETE
per distruggere la risorsa order
. pay
e expedite
sono strutturati come creazione (HTTP POST) di risorse secondarie di payments
e expeditions
sotto risorsa orders
.
Interfacce RESTful modelli di interazione delle applicazioni Web standardizzati per renderli più facili da capire e programmare contro. Poiché le interfacce sono incentrate sulla manipolazione delle risorse, le risposte sono molto più prevedibili. Un’analogia di come il modello di architettura RESTful semplifica l’interazione con i servizi Web sarebbe il modo in cui il database relazionale e il linguaggio SQL semplificano l’archiviazione dei dati. Prima di Database relazionali e SQL, i dati sono stati in genere memorizzati in sistemi proprietari con logica specifica per interagire con loro, questo significava che su ogni progetto si avrebbe dovuto imparare un diverso insieme di istruzioni per interagire con i dati. Database relazionali e SQL ha dato una struttura dati comune (record di dati come righe e colonne memorizzate nelle tabelle) e un insieme di interfacce comuni-quattro semplici verbi di SELECT
, INSERT
, UPDATE
e DELETE
in grado di supportare tutti i tipi di applicazioni.
L’adozione di un’interfaccia RESTful per la tua app Web semplificherà anche l’applicazione per allinearsi con il modo in cui i dati di back-end sono memorizzati nei database e semplifica lo sviluppo. Lo vedremo nei capitoli seguenti.
Notazione delle risorse
Abbiamo parlato delle convenzioni di routing di Rails e dei modelli di URL RESTful. Ora il nostro file routes.rb
sarà simile al seguente:
### config/routes.rb ### Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' ### comments ### get '/comments' => 'comments#index' post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' end
In effetti, i percorsi come quello che abbiamo nella sezione posts
sono molto comuni, quindi Rails fornisce una notazione speciale resources
che aiuta a generarli per te.
Possiamo semplicemente fare:
resources :posts
Questa linea genererà automaticamente le 8 linee che avevamo prima. Si noti che per l’azione update
, Rails consente sia il verbo PUT
che PATCH
, per motivi di compatibilità.
È possibile eseguire bundle exec rake routes
nell’ambiente della riga di comando per verificare che generi esattamente lo stesso insieme di percorsi.
Si noti che questa singola riga genererà 8 percorsi. Nel nostro caso abbiamo bisogno di tutti i percorsi qui, ma se hai solo bisogno di un sottoinsieme dei percorsi, puoi definirli in modo più esplicito come:
resources :posts, only:
Questa riga sopra genererebbe solo 3 percorsi per te-digita bundle exec rake routes
per verificarlo.
Risorse nidificate
Rails ci consente anche di annidare le risorse per creare pattern URL con più risorse, vedi sotto:
### config/routes.rb ### Rails.application.routes.draw do resources :posts do resources :comments, only: end resources :comments, only: :index end
Esegui bundle exec rake routes
e vedi l’output – dovrebbe essere lo stesso di quello che avevamo prima.
Aiutanti percorso
Quando si esegue bundle exec rake routes
, notare la colonna Prefix
per alcuni di questi percorsi. Questi sono qui per aiutarci a sapere come utilizzare gli aiutanti di percorso forniti da Rails per i nostri percorsi. Possiamo usare questi prefissi seguiti da _path
nei nostri controller e viste per creare facilmente percorsi.
Per esempio:
posts_path # => '/posts' post_id = 123 post_comments_path(post_id) # => '/posts/123/comments'
Qual è il vantaggio di utilizzare gli helper URL, piuttosto che codificare i percorsi come /posts/123/comments
direttamente nel codice? (ad esempio, nell’azione del controller?) Il motivo per cui si desidera utilizzare gli helper del percorso è che se si desidera modificare i modelli URL nella propria app, è molto più semplice utilizzare gli helper URL per restituire un percorso diverso: diamo un’occhiata a un esempio:
get '/register', to: 'users#new', as: 'register'
Quando aggiungiamo la clausola ” as ” a questa rotta, se esegui bundle exec rake routes
, vedrai la colonna Prefix
con register
e puoi usare register_path
per ottenere /register
il percorso. Ora, se vogliamo cambiare il percorso in /login
, tutto ciò che dobbiamo fare è solo:
get '/login', to: 'users#new', as: 'register'
Ora il nostro register_path
ci dà /login
. Non dobbiamo cambiare il nostro codice nell’app Rails.
Altre convenzioni di routing
Prima di andare avanti, diamo una rapida occhiata a un paio di varianti di ciò che abbiamo già visto, così come alcune altre funzionalità disponibili in Rails routing:
### config/routes.rb ### Rails.application.routes.draw do # pointing our homepage (root path) to posts#index root to: 'posts#index' # `match` & `via:` allow us to define one route and use several HTTP verbs # `as:` lets us define the name of the route prefix match '/authors/:id' => 'authors#update', via: , as: :update_author # update_author PUT|PATCH /authors/:id(.:format) authors#update resources :posts do # define extra params to pass for requests to a route get 'popular', on: :collection, action: :index, popular: true # popular_posts GET /posts/popular(.:format) posts#index {:popular=>true} get 'preview', on: :member # ... end # we can even use routes to redirect get '/home', to: redirect('/') end
Analizziamo tutte le funzionalità sopra elencate una alla volta.
-
root:
root
viene utilizzato per specificare quale azione mappa a ” / ” (l’URL di livello superiore del nostro sito che non ha percorso).L’URL principale del tuo sito web / app è il più comunemente usato, a causa di questoroot
dovrebbe essere specifiedat nella parte superiore del file routes. -
partita + via:
match
viene utilizzato per abbinare i modelli di URL a uno o più percorsi. Possiamo anche specificare quale verbo HTTP può essere utilizzato per la corrispondenza a un URL con questo modello. Lo facciamo passando un hash al metodomatch
. La chiave per questo hash èvia
e il valore è un array di verbi HTTP.match
è una forma più generale di alcuni metodi di routing HTTP più comunemente utilizzati, comeget
,post
edelete
. Può richiedere tutte le stesse opzioni di questi metodi, ma, rispetto a questi metodi, offre un po ‘ più di flessibilità.
Ad esempio, usandomatch
possiamo specificare un URL che corrisponde a due percorsi diversi, ognuno corrispondente a due diversi verbi HTTP. Normalmente, fare questo richiederebbe due comandi, invece di uno. Possiamo vedere questo dal nostro esempio sopra, dove abbiniamo il pattern URL'/authors/:id'
all’azione'authors#update'
. Specifichiamo quindi quali verbi HTTP possono essere usati per emettere la richiesta per quell’URL convia:
. Specificare sempre un metodo HTTP quando si utilizzamatch
, non farlo può avere implicazioni negative sulla sicurezza dell’applicazione.match
presenta un’altra opzione per il routing a determinate azioni in Rails. In generale, è meglio attenersi ai metodi più comunemente usatiHttpHelpers
, comeget
epost
. -
as: Abbiamo accennato un po ‘ prima che l’opzione
as:
può essere utilizzata con la nostra dichiarazione di route per cambiare il prefisso per i nostri helper URL. Questo può essere utilizzato in vari modi. Possiamo usareas:
per far sì che i nostri aiutanti URL corrispondano meglio agli URL personalizzati. Un altro uso è quello di cambiare l’helper del percorso URL corrente in qualcosa di più intuitivo o qualcosa che corrisponda meglio con le risorse all’interno di un’applicazione. -
percorso di raccolta: vedi come sopra annidiamo il nostro percorso
/popular
sotto la risorsaposts
. Quindi usiamoon: :collection
per specificare quale parte di una risorsa stiamo annidando questa rotta. Abbiamo molti messaggi in modo che è considerato una raccolta. Specificandoon: :collection
stiamo dicendo “Abbina un URL con il percorso/posts/popular
.”Se non abbiamo aggiuntoon: :collection
, Rails assumerà che questo percorso corrisponda a un’altra risorsa associata a un singolo membro della nostra raccolta di post. In tal caso il nostro percorso diventerebbe/posts/:id/popular
. Possiamo anche specificare più percorsi di raccolta utilizzando un formato di blocco.
collection do get 'popular' end
- passaggio di un parametro extra: possiamo specificare un parametro predefinito che viene sempre passato con il nostro hash
params
quando siamo abbinati a determinati URL. Ci sono due modi per specificare questo; un modo è lo stesso modo in cui facciamo sopra:
get 'popular', on: :collection, action: :index, popular: true
popular: true
verrà passato alla nostra azione con cui il percorso popolare corrisponde tramite l’hash params
. Avrà una chiave di :popular
e un valore di true
. Possiamo anche usare una sintassi più esplicita passando un hash al nostro metodo di route get
, dovela chiave è defaults:
e il valore è un altro hash contenente il nome del parametro che vogliamo passare alla nostra azione.
get 'popular', on: :collection, action: :index, defaults: { popular: true}
-
percorso membro: possiamo usare
on: member
per specificare che il nostro percorso corrisponde a un membro di una raccolta. Se usiamo questo il segmento dinamico verrà visualizzato come:id
. Verrà creato anche un helper URL comepreview_post
. Specificando questa rotta conon: member
, stiamo dicendo a Rails che questo è un membro di questa particolare risorsa. Che non è solo un’altra risorsa annidata in post, ma più strettamente legata o correlata ai nostri post in questa applicazione. Più percorsi membri possono essere definiti utilizzando un formato di blocco; questo formato utilizza la stessa sintassi del formato di blocco per definire più percorsi di raccolta, basta sostituirecollection
conmember
. -
redirect: C’è un altro concetto di cui parlare che viene visualizzato nel nostro esempio sopra, e questo è il reindirizzamento. Rails ci dà la possibilità di reindirizzare da un percorso all’altro utilizzando un helper di reindirizzamento in combinazione con un percorso.
get '/home', to: redirect('/')
. Se qualcuno tenta di accedere al percorso/home
, verrà immediatamente reindirizzato al percorso principale/
. Questo non è limitato a un solo percorso URL, ovviamente; potremmo anche avere qualcosa del genere:get '/home', to: redirect('/travel')
.
Recensione
I percorsi Rails si trovano nella parte anteriore di un’applicazione. Un percorso interpreta una richiesta HTTP in entrata e:
- abbina una richiesta a un’azione del controller in base alla combinazione di un verbo HTTP e il pattern URL della richiesta
- acquisisce i dati nell’URL per essere disponibili in
params
nelle azioni del controller - Rails incoraggia gli sviluppatori a utilizzare pattern URL RESTful durante la configurazione dei percorsi, con concettualizzazione della manipolazione delle risorse con verbi HTTP.
- È possibile utilizzare la macro
resources
per generare percorsi RESTful molto rapidamente.