Ruby on Rails
Routing
Ricerca…
introduzione
Osservazioni
"Routing" in generale è il modo in cui gli URL sono "gestiti" dalla tua app. In caso di Rails è in genere il controller e l'azione di quel controller gestirà un particolare URL in arrivo. Nelle app Rails, le rotte vengono di solito collocate nel file config/routes.rb
.
Routing delle risorse (base)
Le rotte sono definite in config/routes.rb
. Sono spesso definiti come un gruppo di percorsi correlati, utilizzando le resources
o i metodi di resource
.
resources :users
creano i seguenti sette percorsi, tutti UsersController
alle azioni di UsersController
:
get '/users', to: 'users#index'
post '/users', to: 'users#create'
get '/users/new', to: 'users#new'
get '/users/:id/edit', to: 'users#edit'
get '/users/:id', to: 'users#show'
patch/put '/users/:id', to: 'users#update'
delete '/users/:id', to: 'users#destroy'
I nomi delle azioni sono visualizzati dopo il #
nel parametro to
sopra. I metodi con gli stessi nomi devono essere definiti in app/controllers/users_controller.rb
come segue:
class UsersController < ApplicationController
def index
end
def create
end
# continue with all the other methods…
end
È possibile limitare le azioni generate only
con o except
:
resources :users, only: [:show]
resources :users, except: [:show, :index]
Puoi visualizzare tutti i percorsi della tua applicazione in qualsiasi momento eseguendo:
$ rake routes
$ rake routes
# OR
$ rails routes
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Per vedere solo le rotte che si associano a un controller particolare:
$ rake routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
$ rake routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
# OR
$ rails routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
Puoi cercare attraverso i percorsi usando l'opzione -g
. Mostra tutte le route che corrispondono parzialmente al nome del metodo helper, al percorso URL o al verbo HTTP:
$ rake routes -g new_user # Matches helper method
$ rake routes -g POST # Matches HTTP Verb POST
$ rake routes -g new_user # Matches helper method
$ rake routes -g POST # Matches HTTP Verb POST
# OR
$ rails routes -g new_user # Matches helper method
$ rails routes -g POST # Matches HTTP Verb POST
Inoltre, quando si esegue il server di rails
in modalità di sviluppo, è possibile accedere a una pagina Web che mostra tutti i percorsi con un filtro di ricerca, abbinato in priorità da cima a fondo, in <hostname>/rails/info/routes
. Sembrerà così:
aiutante | Verbale HTTP | Sentiero | Controller # Azione |
---|---|---|---|
Percorso / Url | [Path Match] | ||
users_path | OTTENERE | /users(.:format) | Indice utenti # |
INVIARE | /users(.:format) | utenti creano # | |
new_user_path | OTTENERE | /users/new(.:format) | utenti # nuova |
edit_user_path | OTTENERE | /users/:id/edit(.:format) | gli utenti # modifica |
user_path | OTTENERE | /users/:id(.:format) | gli utenti # show |
PATCH | /users/:id(.:format) | gli utenti # aggiornamento | |
METTERE | /users/:id(.:format) | gli utenti # aggiornamento | |
ELIMINA | /users/:id(.:format) | utenti # distruggono |
Le route possono essere dichiarate disponibili solo per i membri (non per le raccolte) utilizzando la resource
metodo anziché le resources
in routes.rb
. Con la resource
, una route index
non viene creata per impostazione predefinita, ma solo quando ne viene richiesta esplicitamente una come questa:
resource :orders, only: [:index, :create, :show]
vincoli
Puoi filtrare quali percorsi sono disponibili usando i vincoli.
Esistono diversi modi per utilizzare i vincoli, tra cui:
Ad esempio, un vincolo basato su richiesta per consentire solo a un indirizzo IP specifico di accedere a una rotta:
constraints(ip: /127\.0\.0\.1$/) do
get 'route', to: "controller#action"
end
Vedi altri esempi simili ActionDispatch :: Routing :: Mapper :: Scoping .
Se vuoi fare qualcosa di più complesso puoi usare vincoli più avanzati e creare una classe per avvolgere la logica:
# lib/api_version_constraint.rb
class ApiVersionConstraint
def initialize(version:, default:)
@version = version
@default = default
end
def version_header
"application/vnd.my-app.v#{@version}"
end
def matches?(request)
@default || request.headers["Accept"].include?(version_header)
end
end
# config/routes.rb
require "api_version_constraint"
Rails.application.routes.draw do
namespace :v1, constraints: ApiVersionConstraint.new(version: 1, default: true) do
resources :users # Will route to app/controllers/v1/users_controller.rb
end
namespace :v2, constraints: ApiVersionConstraint.new(version: 2) do
resources :users # Will route to app/controllers/v2/users_controller.rb
end
end
Un modulo, diversi pulsanti di invio
È inoltre possibile utilizzare il valore dei tag di invio di un modulo come vincolo per eseguire il routing a un'azione diversa. Se hai un modulo con più pulsanti di invio (ad esempio "anteprima" e "invia"), puoi catturare questo vincolo direttamente nel tuo routes.rb
, invece di scrivere javascript per modificare l'URL di destinazione del modulo. Ad esempio con la gem di commit_param_routing puoi sfruttare i binari submit_tag
submit_tag
parametro submit_tag
Rails consente di modificare il valore del parametro di commit della submit_tag
# app/views/orders/mass_order.html.erb
<%= form_for(@orders, url: mass_create_order_path do |f| %>
<!-- Big form here -->
<%= submit_tag "Preview" %>
<%= submit_tag "Submit" %>
# => <input name="commit" type="submit" value="Preview" />
# => <input name="commit" type="submit" value="Submit" />
...
<% end %>
# config/routes.rb
resources :orders do
# Both routes below describe the same POST URL, but route to different actions
post 'mass_order', on: :collection, as: 'mass_order',
constraints: CommitParamRouting.new('Submit'), action: 'mass_create' # when the user presses "submit"
post 'mass_order', on: :collection,
constraints: CommitParamRouting.new('Preview'), action: 'mass_create_preview' # when the user presses "preview"
# Note the `as:` is defined only once, since the path helper is mass_create_order_path for the form url
# CommitParamRouting is just a class like ApiVersionContraint
end
Percorsi di ricerca
Rails offre diversi modi per organizzare i tuoi percorsi.
Ambito per URL :
scope 'admin' do
get 'dashboard', to: 'administration#dashboard'
resources 'employees'
end
Questo genera i seguenti percorsi
get '/admin/dashboard', to: 'administration#dashboard'
post '/admin/employees', to: 'employees#create'
get '/admin/employees/new', to: 'employees#new'
get '/admin/employees/:id/edit', to: 'employees#edit'
get '/admin/employees/:id', to: 'employees#show'
patch/put '/admin/employees/:id', to: 'employees#update'
delete '/admin/employees/:id', to: 'employees#destroy'
Potrebbe avere più senso, sul lato server, mantenere alcune viste in una sottocartella diversa, per separare le viste di amministrazione dalle viste degli utenti.
Ambito per modulo
scope module: :admin do
get 'dashboard', to: 'administration#dashboard'
end
module
cerca i file del controller sotto la sottocartella del nome specificato
get '/dashboard', to: 'admin/administration#dashboard'
È possibile rinominare il prefisso degli helper del percorso aggiungendo un parametro as
scope 'admin', as: :administration do
get 'dashboard'
end
# => administration_dashboard_path
Rails fornisce un modo conveniente per fare tutto quanto sopra, usando il metodo namespace
. Le seguenti dichiarazioni sono equivalenti
namespace :admin do
end
scope 'admin', module: :admin, as: :admin
Ambito dal controller
scope controller: :management do
get 'dashboard'
get 'performance'
end
Questo genera queste rotte
get '/dashboard', to: 'management#dashboard'
get '/performance', to: 'management#performance'
Nidificazione superficiale
Le rotte delle risorse accettano una :shallow
opzione :shallow
che aiuta ad accorciare gli URL laddove possibile. Le risorse non devono essere nidificate a più di un livello. Un modo per evitare questo è creare percorsi poco profondi. L'obiettivo è quello di lasciare i segmenti URL della raccolta principale dove non sono necessari. Il risultato finale è che le sole rotte nidificate generate sono per :index
:create
e :new
azioni. Il resto è tenuto nel proprio contesto URL poco profondo. Ci sono due opzioni per l'ambito di percorsi superficiali personalizzati:
: shallow_path : prefissa i percorsi dei membri con un parametro specificato
scope shallow_path: "sekret" do resources :articles do resources :comments, shallow: true end end
: shallow_prefix : aggiunge i parametri specificati agli helper specificati
scope shallow_prefix: "sekret" do resources :articles do resources :comments, shallow: true end end
Possiamo anche illustrare i percorsi shallow
più:
resources :auctions, shallow: true do
resources :bids do
resources :comments
end
end
in alternativa codificato come segue (se sei felice del blocco):
resources :auctions do
shallow do
resources :bids do
resources :comments
end
end
end
I percorsi risultanti sono:
Prefisso | Verbo | Pattern URI |
---|---|---|
bid_comments | OTTENERE | /bids/:bid_id/comments(.:format) |
INVIARE | /bids/:bid_id/comments(.:format) | |
new_bid_comment | OTTENERE | /bids/:bid_id/comments/new(.:format) |
edit_comment | OTTENERE | /comments/:id/edit(.:format) |
commento | OTTENERE | /comments/:id(.:format) |
PATCH | /comments/:id(.:format) | |
METTERE | /comments/:id(.:format) | |
ELIMINA | /comments/:id(.:format) | |
auction_bids | OTTENERE | /auctions/:auction_id/bids(.:format) |
INVIARE | /auctions/:auction_id/bids(.:format) | |
new_auction_bid | OTTENERE | /auctions/:auction_id/bids/new(.:format) |
edit_bid | OTTENERE | /bids/:id/edit(.:format) |
offerta | OTTENERE | /bids/:id(.:format) |
PATCH | /bids/:id(.:format) | |
METTERE | /bids/:id(.:format) | |
ELIMINA | /bids/:id(.:format) | |
aste | OTTENERE | /auctions(.:format) |
INVIARE | /auctions(.:format) | |
new_auction | OTTENERE | /auctions/new(.:format) |
edit_auction | OTTENERE | /auctions/:id/edit(.:format) |
vendita all'asta | OTTENERE | /auctions/:id(.:format) |
PATCH | /auctions/:id(.:format) | |
METTERE | /auctions/:id(.:format) | |
ELIMINA | /auctions/:id(.:format) |
Se analizzi attentamente le rotte generate, noterai che le parti annidate dell'URL sono incluse solo quando sono necessarie per determinare quali dati visualizzare.
preoccupazioni
Per evitare la ripetizione in percorsi nidificati, le preoccupazioni forniscono un ottimo modo per condividere risorse comuni che sono riutilizzabili. Per creare un problema, utilizzare la concern
del metodo all'interno del file routes.rb
. Il metodo si aspetta un simbolo e un blocco:
concern :commentable do
resources :comments
end
Pur non creando alcuna route, questo codice consente di utilizzare l'attributo :concerns
su una risorsa. L'esempio più semplice sarebbe:
resource :page, concerns: :commentable
La risorsa nidificata equivalente sarebbe simile a questa:
resource :page do
resource :comments
end
Ciò creerebbe, ad esempio, i seguenti percorsi:
/pages/#{page_id}/comments
/pages/#{page_id}/comments/#{comment_id}
Affinché le preoccupazioni siano significative, devono esserci più risorse che utilizzano la preoccupazione. Risorse aggiuntive potrebbero utilizzare una qualsiasi delle seguenti sintassi per chiamare la preoccupazione:
resource :post, concerns: %i(commentable)
resource :blog do
concerns :commentable
end
reindirizzamento
È possibile eseguire il reindirizzamento nei percorsi di Rails come segue:
get '/stories', to: redirect('/posts')
match "/abc" => redirect("http://example.com/abc")
Puoi anche reindirizzare tutte le rotte sconosciute ad un determinato percorso:
match '*path' => redirect('/'), via: :get
# or
get '*path' => redirect('/')
match '*path' => redirect('/')
Percorsi membro e raccolta
La definizione di un blocco membro all'interno di una risorsa crea una route che può agire su un singolo membro di quella rotta basata su risorse:
resources :posts do
member do
get 'preview'
end
end
Questo genera il seguente percorso membro:
get '/posts/:id/preview', to: 'posts#preview'
# preview_post_path
I percorsi di raccolta consentono di creare percorsi che possono agire su una raccolta di oggetti risorsa:
resources :posts do
collection do
get 'search'
end
end
Questo genera il seguente percorso di raccolta:
get '/posts/search', to: 'posts#search'
# search_posts_path
Una sintassi alternativa:
resources :posts do
get 'preview', on: :member
get 'search', on: :collection
end
Param di URL con un punto
Se si desidera supportare un parametro url più complesso di un numero id, è possibile che si verifichi un problema con il parser se il valore contiene un punto. Si presuppone che qualsiasi cosa che segue un periodo sia un formato (es. Json, xml).
È possibile aggirare questa limitazione utilizzando un vincolo per ampliare l'input accettato.
Ad esempio, se desideri fare riferimento a un record utente tramite indirizzo email nell'URL:
resources :users, constraints: { id: /.*/ }
Root route
Puoi aggiungere un percorso della home page alla tua app con il metodo root
.
# config/routes.rb
Rails.application.routes.draw do
root "application#index"
# equivalent to:
# get "/", "application#index"
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def index
render "homepage"
end
end
E in terminal, i rake routes
( rails routes
di rails in Rails 5) produrranno:
root GET / application#index
Poiché la home page è in genere il percorso più importante e le route sono prioritarie nell'ordine in cui vengono visualizzate, la route root
dovrebbe essere in genere la prima nel file dei percorsi.
Ulteriori azioni RESTful
resources :photos do member do get 'preview' end collection do get 'dashboard' end end
Questo crea i seguenti percorsi oltre alle 7 rotte RESTful predefinite :
get '/photos/:id/preview', to: 'photos#preview'
get '/photos/dashboards', to: 'photos#dashboard'
Se vuoi farlo per linee singole, puoi usare:
resources :photos do get 'preview', on: :member get 'dashboard', on: :collection end
Puoi anche aggiungere un'azione al /new
percorso:
resources :photos do get 'preview', on: :new end
Che creerà:
get '/photos/new/preview', to: 'photos#preview'
Sii consapevole quando aggiungi azioni ai tuoi percorsi RESTful, probabilmente ti manca un'altra risorsa!
Scope disponibili locales
Se la tua applicazione è disponibile in diverse lingue, di solito mostri la locale corrente nell'URL.
scope '/(:locale)', locale: /#{I18n.available_locales.join('|')}/ do
root 'example#root'
# other routes
end
La tua radice sarà accessibile tramite le impostazioni locali definite in I18n.available_locales
.
Montare un'altra applicazione
mount viene utilizzato per montare un'altra applicazione (fondamentalmente un'applicazione rack) o motori di rotaia da utilizzare all'interno dell'applicazione corrente
sintassi:
mount SomeRackApp, at: "some_route"
Ora puoi accedere all'applicazione montata sopra utilizzando helper some_rack_app_path
o some_rack_app_url
.
Ma se vuoi rinominare questo nome helper puoi farlo come:
mount SomeRackApp, at: "some_route", as: :myapp
Questo genererà gli myapp_path
e myapp_url
che possono essere utilizzati per navigare in questa app montata.
Reindirizzamenti e percorsi Wildcard
Se desideri fornire un URL per comodità all'utente, ma mappalo direttamente a un altro che stai già utilizzando. Utilizza un reindirizzamento:
# config/routes.rb
TestApp::Application.routes.draw do
get 'courses/:course_name' => redirect('/courses/%{course_name}/lessons'), :as => "course"
end
Bene, è diventato interessante velocemente. Il principio di base qui è utilizzare semplicemente il metodo #redirect
per inviare una rotta a un'altra rotta. Se il tuo percorso è abbastanza semplice, è un metodo davvero semplice. Ma se vuoi anche inviare i parametri originali, devi fare un po 'di ginnastica catturando il parametro all'interno di %{here}
. Nota le singole virgolette attorno a tutto.
Nell'esempio sopra, abbiamo anche rinominato la rotta per comodità usando un alias con: come parametro. Questo ci permette di usare quel nome in metodi come gli helper #_path. Di nuovo, prova le tue $ rake routes
con domande.
Suddividi i percorsi in più file
Se il tuo file di rotte è enormemente grande, puoi inserire i tuoi percorsi in più file e includere ognuno dei file con il metodo require_relative
di Ruby:
config/routes.rb
: YourAppName::Application.routes.draw do
require_relative 'routes/admin_routes'
require_relative 'routes/sidekiq_routes'
require_relative 'routes/api_routes'
require_relative 'routes/your_app_routes'
end
config/routes/api_routes.rb
: YourAppName::Application.routes.draw do
namespace :api do
# ...
end
end
Percorsi nidificati
Se si desidera aggiungere rotte nidificate, è possibile scrivere il seguente codice nel file routes.rb
.
resources :admins do
resources :employees
end
Questo genererà i seguenti percorsi:
admin_employees GET /admins/:admin_id/employees(.:format) employees#index
POST /admins/:admin_id/employees(.:format) employees#create
new_admin_employee GET /admins/:admin_id/employees/new(.:format) employees#new
edit_admin_employee GET /admins/:admin_id/employees/:id/edit(.:format) employees#edit
admin_employee GET /admins/:admin_id/employees/:id(.:format) employees#show
PATCH /admins/:admin_id/employees/:id(.:format) employees#update
PUT /admins/:admin_id/employees/:id(.:format) employees#update
DELETE /admins/:admin_id/employees/:id(.:format) employees#destroy
admins GET /admins(.:format) admins#index
POST /admins(.:format) admins#create
new_admin GET /admins/new(.:format) admins#new
edit_admin GET /admins/:id/edit(.:format) admins#edit
admin GET /admins/:id(.:format) admins#show
PATCH /admins/:id(.:format) admins#update
PUT /admins/:id(.:format) admins#update
DELETE /admins/:id(.:format) admins#destroy