-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Semantically and functionally enhance routes to provide extended configurations.
Example
# config/routes.rb
Rails.application.routes.draw do
admin do # 1.
resources :users do # 2.
action :approve # 3.
action :toggle, as: [:enable, :disable] # 4.
action :change_password, view: true # 5.
member do # 6.
action :impersonate
end
end
resources :orders, actions: [:accept, :ship] # 7.
section :store do # 8.
dashboard cards: [:sells, :views] # 9.
end
authenticate :users, with: :devise # 10.
end
admin :internal, path: :system do # 11.
resources :admin_users
simple do # 12.
resources :categories
end
unauthenticated do # 13.
get 'uptime', to: 'rails/health#show', as: :rails_health_check
end
searchable :templates # 14.
authenticate :admin_user, with: :rails
end
endOutput
$ rails routesPrefix Verb URI Pattern Controller#Action
admin /admin Torque::Admin[:admin]
internal /system Torque::Admin[:internal]
root GET / application#index
Routes for Torque::Admin[:admin]:
approve_users PATCH /users(/:id)/approve(.:format) admin/users#approve
enable_users PATCH /users(/:id)/enable(.:format) admin/users#toggle
disable_users PATCH /users(/:id)/disable(.:format) admin/users#toggle
change_password_users PATCH /users(/:id)/change_password(.:format) admin/users#change_password
GET /users(/:id)/change_password(.:format) admin/users#change_password
DELETE /users(/:id)(.:format) admin/users#destroy
impersonate_user PATCH /users/:id/impersonate(.:format) admin/users#impersonate
preview_user GET /users/:id/preview(.:format) admin/users#preview
edit_user GET /users/:id/edit(.:format) admin/users#edit
user GET /users/:id(.:format) admin/users#show
PATCH /users/:id(.:format) admin/users#update
PUT /users/:id(.:format) admin/users#update
search_users GET /users/search(.:format) admin/users#search
new_user GET /users/new(.:format) admin/users#new
users GET /users(.:format) admin/users#index
POST /users(.:format) admin/users#create
PATCH /users(.:format) admin/users#upsert
accept_orders PATCH /orders(/:id)/accept(.:format) admin/orders#accept
ship_orders PATCH /orders(/:id)/ship(.:format) admin/orders#ship
DELETE /orders(/:id)(.:format) admin/orders#destroy
preview_order GET /orders/:id/preview(.:format) admin/orders#preview
edit_order GET /orders/:id/edit(.:format) admin/orders#edit
order GET /orders/:id(.:format) admin/orders#show
PATCH /orders/:id(.:format) admin/orders#update
PUT /orders/:id(.:format) admin/orders#update
search_orders GET /orders/search(.:format) admin/orders#search
new_order GET /orders/new(.:format) admin/orders#new
orders GET /orders(.:format) admin/orders#index
POST /orders(.:format) admin/orders#create
PATCH /orders(.:format) admin/orders#upsert
GET /store(.:format) redirect(301, /store/dashboard)
store_dashboard GET /store/dashboard(.:format) admin/store_dashboard#index
store_dashboard_stock GET /store/dashboard/stock(.:format) admin/store_dashboard#stock
store_dashboard_products GET /store/dashboard/products(.:format) admin/store_dashboard#products
DELETE /store/products(/:id)(.:format) admin/products#destroy
preview_store_product GET /store/products/:id/preview(.:format) admin/products#preview
edit_store_product GET /store/products/:id/edit(.:format) admin/products#edit
store_product GET /store/products/:id(.:format) admin/products#show
PATCH /store/products/:id(.:format) admin/products#update
PUT /store/products/:id(.:format) admin/products#update
search_store_products GET /store/products/search(.:format) admin/products#search
new_store_product GET /store/products/new(.:format) admin/products#new
store_products GET /store/products(.:format) admin/products#index
POST /store/products(.:format) admin/products#create
PATCH /store/products(.:format) admin/products#upsert
new_user_session GET /login(.:format) admin/sessions#new
user_session POST /login(.:format) admin/sessions#create
destroy_user_session DELETE /logout(.:format) admin/sessions#destroy
new_user_password GET /password/new(.:format) admin/passwords#new
edit_user_password GET /password/edit(.:format) admin/passwords#edit
user_password PATCH /password(.:format) admin/passwords#update
PUT /password(.:format) admin/passwords#update
POST /password(.:format) admin/passwords#create
cancel_user_registration GET /cancel(.:format) admin/registrations#cancel
new_user_registration GET /sign_up(.:format) admin/registrations#new
edit_user_registration GET /edit(.:format) admin/registrations#edit
user_registration PATCH / admin/registrations#update
PUT / admin/registrations#update
DELETE / admin/registrations#destroy
POST / admin/registrations#create
new_user_confirmation GET /confirmation/new(.:format) admin/confirmations#new
user_confirmation GET /confirmation(.:format) admin/confirmations#show
POST /confirmation(.:format) admin/confirmations#create
new_user_unlock GET /unlock/new(.:format) admin/unlocks#new
user_unlock GET /unlock(.:format) admin/unlocks#show
POST /unlock(.:format) admin/unlocks#create
GET /(.:format) redirect(301, /dashboard)
dashboard GET /dashboard(.:format) admin/dashboard#index
Routes for Torque::Admin[:internal]:
DELETE /admin_users(/:id)(.:format) internal/admin_users#destroy
preview_admin_user GET /admin_users/:id/preview(.:format) internal/admin_users#preview
edit_admin_user GET /admin_users/:id/edit(.:format) internal/admin_users#edit
admin_user GET /admin_users/:id(.:format) internal/admin_users#show
PATCH /admin_users/:id(.:format) internal/admin_users#update
PUT /admin_users/:id(.:format) internal/admin_users#update
search_admin_users GET /admin_users/search(.:format) internal/admin_users#search
new_admin_user GET /admin_users/new(.:format) internal/admin_users#new
admin_users GET /admin_users(.:format) internal/admin_users#index
POST /admin_users(.:format) internal/admin_users#create
PATCH /admin_users(.:format) internal/admin_users#upsert
DELETE /categories(/:id)(.:format) internal/simple_resource#destroy
edit_category GET /categories/:id/edit(.:format) internal/simple_resource#edit
category GET /categories/:id(.:format) internal/simple_resource#show
PATCH /categories/:id(.:format) internal/simple_resource#update
PUT /categories/:id(.:format) internal/simple_resource#update
search_categories GET /categories/search(.:format) internal/simple_resource#search
new_category GET /categories/new(.:format) internal/simple_resource#new
categories GET /categories(.:format) internal/simple_resource#index
POST /categories(.:format) internal/simple_resource#create
PATCH /categories(.:format) internal/simple_resource#upsert
rails_health_check GET /uptime(.:format) * rails/health#show
new_session GET /session/new(.:format) internal/sessions#new
edit_session GET /session/edit(.:format) internal/sessions#edit
session GET /session(.:format) internal/sessions#show
PATCH /session(.:format) internal/sessions#update
PUT /session(.:format) internal/sessions#update
DELETE /session(.:format) internal/sessions#destroy
POST /session(.:format) internal/sessions#create
passwords GET /passwords(.:format) internal/passwords#index
POST /passwords(.:format) internal/passwords#create
new_password GET /passwords/new(.:format) internal/passwords#new
edit_password GET /passwords/:token/edit(.:format) internal/passwords#edit
password GET /passwords/:token(.:format) internal/passwords#show
PATCH /passwords/:token(.:format) internal/passwords#update
PUT /passwords/:token(.:format) internal/passwords#update
DELETE /passwords/:token(.:format) internal/passwords#destroy
search_templates GET /templates/search(.:format) internal/simple_resource#search
GET /(.:format) redirect(301, /dashboard)
dashboard GET /dashboard(.:format) internal/dashboard#index
This might not be 100% accurate due to additional customization and sorting
1. The admin definition
This method will define a new admin. An extended config file may or may not exist on an initializer (like config/initializers/admin.rb). It automatically sets a new Engine, proper namespace, and any necessary Torque::Admin::Application configurations.
2. Extended resources
For the most part, this will behave like a standard Rails resources definition. However, notice some small changes and additions:
destroyis now a member and collection action, meaning it can handle a single ID or multiple IDs (more on that later).previewis a new member action intended for situations where we want a quick snip (probably a modal or similar) of a record.searchis a new collection action intended for searching/filtering records, resulting in a list of options.upsertis a new collection action intended for creating or updating multiple records at once.
3. Resource(s) actions
Resource(s) can be defined with multiple actions. They represent operations that can be performed on one or more records at once. This is the same mechanism by which destroy was moved to.
4. Multiple paths, same action
This is quite frequent, and such features address the need for multiple actions doing similar things, or for a single action with an improper path or intention. Metadata may be provided, giving the exact action_path that triggered the action, for a more specific handling.
5. Actions that display a view first
Sometimes an action may require a form that provides more information before proceeding. In such cases, the action may be defined with view: true, which indicates what should happen depending on the HTTP VERB.
6. Expected behavior with Rails defaults
If actions need to be tied exclusively to a member or only via collection, it can by done by using the on: option, or using member and collection blocks. The behavior of these options is the same as in Rails defaults.
7. Quick definitions
The actions argument simplifies the definition of multiple actions. It also allows sharing behavior across different resources.
This can allow a wide range of possibilities. For example, you can define a Concern, add it to multiple controllers, and then use actions with a constant to all those resources. It can even be dynamic using .public_instance_methods.
One side note, this is applied before except and only options, so those can still be used to further limit the actions created.
8. A simple organizational shorthand
It's just a simple scope path: VALUE, as: VALUE when we want to organize routes and helpers without nesting controllers. It also helps when building an automatic menu.
9. A new type of "resource"
Dashboards are intended to be a landing page for an admin or a section of an admin. They are not tied to a model, but rather to a set of widgets that display information.
Although the dashboard can display multiple cards at the same time, cards allows defining multiple endpoints that can be loaded asynchronously or even updated periodically.
10. Authentication sugar syntax
This is just a shorthand for defining authentication routes, which are common in admin interfaces. It sets up routes for login, logout, password reset, and registration.
Each provider (defined by the mandatory with: key) will have its own set of routes, allowing for multiple authentication methods within the same admin interface.
11. Multiple admin applications under the same Rails
It's possible to define multiple admin applications within the same Rails application. Each admin will have its own namespace, engine, and configurations.
They will operate independently in all respects. They can have different authentication methods, different frontend frameworks, different everything.
12. The key to reducing pointless controllers
More often than not, admin interfaces require a lot of boilerplate controllers that do very little beyond the standard CRUD operations. With this routing DSL, you can define resources and actions without creating a controller.
It will simply be handled by the default and base controller Torque::Admin::ResourceController with default properties.
This also drops the preview routes, since they're less likely to be needed.
13. Very clear indication of public routes
Admins are in an authenticated area by default. However, there are cases where some routes must be public (e.g., login and registration). This will explicitly do this job, without adding any route constraints or anything like that. It will simply add an extra internal metadata indication that an authenticated user is not necessary.
14. Not fully manageable resources
Sometimes there are resources that we don't need to manage, there is no need for pages and forms or anything like that. But, those resources tend to be the ones we need to at least give as select options or reference on filters. That is another time that we can take advantage of the simple_resource.
Notes
- Because the
Torque::Admin::Applications are heavily controlled under their own namespace, controllers do not necessarily need to exist. The application will seamlessly fallback to the default behavior (controllers will be defined automatically if not found). - Since this is simply built on top of Rails routing DSL, all standard Rails routing features are available and work as expected.
- You won't be able to define an admin inside another admin. Each admin is a top-level definition. But other engines can be nested inside an admin.
A word about meta information
The admin is being implemented on something that I call "continuous definition", where the definition and full setup of an admin is not found in one place, but rather spread across multiple files and locations. This is done deliberately to give the feel of an extended Rails application, not to teach something completely new.
That said, the Admin application will continuously collect meta information about itself and store it internally for later use. In the example, admin application will be aware that it has users, orders, and products as managed resources, and that is primarly authenticated via an users resource.
This metadata is used throughout the admin application to enable features such as automatic menu generation, cross-referencing, and more.
Metadata
Metadata
Assignees
Labels
Projects
Status