Class: Rage::Router::DSL::Handler

Overview

This class implements routing logic for your application, providing an API similar to Rails.

Compared to the Rails router, the most notable difference is that a wildcard segment can only be in the last section of the path and cannot be named. Example:

get "/photos/*"

Also, as this is an API-only framework, route helpers, like photos_path or photos_url are not being generated.

Constraints

Currently, the only constraint supported is the host constraint. The constraint value can be either string or a regular expression. Example:

get "/photos", to: "photos#index", constraints: { host: "myhost.com" }

Parameter constraints are likely to be added in the future versions. Custom/lambda constraints are unlikely to be ever added.

Examples:

Set up a root handler

root to: "pages#main"

Set up multiple resources

resources :magazines do
  resources :ads
end

Scope a set of routes to the given default options.

scope path: ":account_id" do
  resources :projects
end

Scope routes to a specific namespace.

namespace :admin do
  resources :posts
end

Instance Method Summary collapse

Instance Method Details

#collection(&block) ⇒ Object

Add a route to the collection.

Examples:

Add a photos/search path instead of photos/:photo_id/search

resources :photos do
  collection do
    get "search"
  end
end


297
298
299
300
301
302
# File 'lib/rage/router/dsl.rb', line 297

def collection(&block)
  orig_path_prefixes = @path_prefixes
  @path_prefixes = @path_prefixes[0...-1] if @path_prefixes.last&.start_with?(":")
  instance_eval(&block)
  @path_prefixes = orig_path_prefixes
end

#controller(controller, &block) ⇒ Object

Scopes routes to a specific controller.

Examples:

controller "photos" do
  post "like"
  post "dislike"
end


283
284
285
286
287
# File 'lib/rage/router/dsl.rb', line 283

def controller(controller, &block)
  @controllers << controller
  instance_eval(&block)
  @controllers.pop
end

#defaults(defaults, &block) ⇒ Object

Specify default parameters for a set of routes.

Examples:

defaults id: "-1", format: "jpg" do
  get "photos/(:id)", to: "photos#index"
end

Parameters:

  • defaults (Hash)

    a hash of default parameters



270
271
272
273
274
# File 'lib/rage/router/dsl.rb', line 270

def defaults(defaults, &block)
  @defaults << defaults
  instance_eval(&block)
  @defaults.pop
end

#delete(path, to: nil, constraints: nil, defaults: nil, on: nil) ⇒ Object

Register a new DELETE route.

Examples:

delete "/photos/:id", to: "photos#destroy", constraints: { host: /myhost/ }
delete "/photos(/:id)", to: "photos#destroy", defaults: { id: "-1" }

Parameters:

  • path (String)

    the path for the route handler

  • to (String) (defaults to: nil)

    the route handler in the format of "controller#action"

  • constraints (Hash) (defaults to: nil)

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • on (nil, :member, :collection) (defaults to: nil)

    a shorthand for wrapping routes in a specific RESTful context



145
146
147
# File 'lib/rage/router/dsl.rb', line 145

def delete(path, to: nil, constraints: nil, defaults: nil, on: nil)
  __with_on_scope(on) { __on("DELETE", path, to, constraints, defaults) }
end

#get(path, to: nil, constraints: nil, defaults: nil, on: nil) ⇒ Object

Register a new GET route.

Examples:

get "/photos/:id", to: "photos#show", constraints: { host: /myhost/ }
get "/photos(/:id)", to: "photos#show", defaults: { id: "-1" }

Parameters:

  • path (String)

    the path for the route handler

  • to (String) (defaults to: nil)

    the route handler in the format of "controller#action"

  • constraints (Hash) (defaults to: nil)

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • on (nil, :member, :collection) (defaults to: nil)

    a shorthand for wrapping routes in a specific RESTful context



85
86
87
# File 'lib/rage/router/dsl.rb', line 85

def get(path, to: nil, constraints: nil, defaults: nil, on: nil)
  __with_on_scope(on) { __on("GET", path, to, constraints, defaults) }
end

#match(path, to:, constraints: {}, defaults: nil, via: :all) ⇒ Object

Match a URL pattern to one or more routes.

Examples:

match "/photos/:id", to: "photos#show", via: [:get, :post]
match "/photos/:id", to: "photos#show", via: :all
match "/health", to: -> (env) { [200, {}, ["healthy"]] }

Parameters:

  • path (String)

    the path for the route handler

  • to (String, #call)

    the route handler in the format of "controller#action" or a callable

  • constraints (Hash) (defaults to: {})

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • via (Symbol, Array<Symbol>) (defaults to: :all)

    an array of HTTP methods to accept



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rage/router/dsl.rb', line 171

def match(path, to:, constraints: {}, defaults: nil, via: :all)
  # via is either nil, or an array of symbols or its :all
  http_methods = via
  # if its :all or nil, then we use the default HTTP methods
  if via == :all || via.nil?
    http_methods = @default_match_methods
  else
    # if its an array of symbols, then we use the symbols as HTTP methods
    http_methods = Array(via)
    # then we check if the HTTP methods are valid
    http_methods.each do |method|
      raise ArgumentError, "Invalid HTTP method: #{method}" unless @default_match_methods.include?(method)
    end
  end

  http_methods.each do |method|
    __on(method.to_s.upcase, path, to, constraints, defaults)
  end
end

#member(&block) ⇒ Object

Add a member route.

Examples:

Add a photos/:id/preview path instead of photos/:photo_id/preview

resources :photos do
  member do
    get "preview"
  end
end


312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/rage/router/dsl.rb', line 312

def member(&block)
  orig_path_prefixes = @path_prefixes

  if (param_prefix = @path_prefixes.last)&.start_with?(":") && @controllers.any?
    member_prefix = param_prefix.delete_prefix(":#{to_singular(@controllers.last)}_")
    @path_prefixes = [*@path_prefixes[0...-1], ":#{member_prefix}"]
  end

  instance_eval(&block)

  @path_prefixes = orig_path_prefixes
end

#mount(app, at:, via: :all) ⇒ Object

Mount a Rack-based application to be used within the application.

Examples:

mount Sidekiq::Web => "/sidekiq"
mount Sidekiq::Web, at: "/sidekiq", via: :get


382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/rage/router/dsl.rb', line 382

def mount(app, at:, via: :all)
  at = "/#{at}" unless at.start_with?("/")
  at = at.delete_suffix("/") if at.end_with?("/")

  http_methods = if via == :all || via.nil?
    @default_match_methods.map { |method| method.to_s.upcase! }
  else
    Array(via).map! do |method|
      raise ArgumentError, "Invalid HTTP method: #{method}" unless @default_match_methods.include?(method)
      method.to_s.upcase!
    end
  end

  @router.mount(at, app, http_methods)
end

#namespace(path, **options, &block) ⇒ Object

Register a new namespace.

Examples:

namespace :admin do
  get "/photos", to: "photos#index"
end
namespace :admin, path: "panel" do
  get "/photos", to: "photos#index"
end
namespace :admin, module: "admin" do
  get "/photos", to: "photos#index"
end

Parameters:

  • path (String)

    the path for the namespace

  • options (Hash)

    a hash of options for the namespace

Options Hash (**options):

  • :module (String)

    the module name for the namespace

  • :path (String)

    the path for the namespace



209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/rage/router/dsl.rb', line 209

def namespace(path, **options, &block)
  path_prefix = options[:path] || path
  module_prefix = options[:module] || path

  @path_prefixes << path_prefix
  @module_prefixes << module_prefix

  instance_eval(&block)

  @path_prefixes.pop
  @module_prefixes.pop
end

#patch(path, to: nil, constraints: nil, defaults: nil, on: nil) ⇒ Object

Register a new PATCH route.

Examples:

patch "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
patch "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }

Parameters:

  • path (String)

    the path for the route handler

  • to (String) (defaults to: nil)

    the route handler in the format of "controller#action"

  • constraints (Hash) (defaults to: nil)

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • on (nil, :member, :collection) (defaults to: nil)

    a shorthand for wrapping routes in a specific RESTful context



130
131
132
# File 'lib/rage/router/dsl.rb', line 130

def patch(path, to: nil, constraints: nil, defaults: nil, on: nil)
  __with_on_scope(on) { __on("PATCH", path, to, constraints, defaults) }
end

#post(path, to: nil, constraints: nil, defaults: nil, on: nil) ⇒ Object

Register a new POST route.

Examples:

post "/photos", to: "photos#create", constraints: { host: /myhost/ }
post "/photos", to: "photos#create", defaults: { format: "jpg" }

Parameters:

  • path (String)

    the path for the route handler

  • to (String) (defaults to: nil)

    the route handler in the format of "controller#action"

  • constraints (Hash) (defaults to: nil)

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • on (nil, :member, :collection) (defaults to: nil)

    a shorthand for wrapping routes in a specific RESTful context



100
101
102
# File 'lib/rage/router/dsl.rb', line 100

def post(path, to: nil, constraints: nil, defaults: nil, on: nil)
  __with_on_scope(on) { __on("POST", path, to, constraints, defaults) }
end

#put(path, to: nil, constraints: nil, defaults: nil, on: nil) ⇒ Object

Register a new PUT route.

Examples:

put "/photos/:id", to: "photos#update", constraints: { host: /myhost/ }
put "/photos(/:id)", to: "photos#update", defaults: { id: "-1" }

Parameters:

  • path (String)

    the path for the route handler

  • to (String) (defaults to: nil)

    the route handler in the format of "controller#action"

  • constraints (Hash) (defaults to: nil)

    a hash of constraints for the route

  • defaults (Hash) (defaults to: nil)

    a hash of default parameters for the route

  • on (nil, :member, :collection) (defaults to: nil)

    a shorthand for wrapping routes in a specific RESTful context



115
116
117
# File 'lib/rage/router/dsl.rb', line 115

def put(path, to: nil, constraints: nil, defaults: nil, on: nil)
  __with_on_scope(on) { __on("PUT", path, to, constraints, defaults) }
end

#resources(*_resources, **opts, &block) ⇒ Object

Note:

This helper doesn't generate the new and edit routes.

Automatically create REST routes for a resource.

Examples:

Create five REST routes, all mapping to the Photos controller:

resources :photos
# GET       /photos       => photos#index
# POST      /photos       => photos#create
# GET       /photos/:id   => photos#show
# PATCH/PUT /photos/:id   => photos#update
# DELETE    /photos/:id   => photos#destroy

Parameters:

  • opts (Hash)

    resource options

Options Hash (**opts):

  • :module (String)

    the namespace for the controller

  • :path (String)

    the path prefix for the routes

  • :only (Symbol, Array<Symbol>)

    only generate routes for the given actions

  • :except (Symbol, Array<Symbol>)

    generate all routes except for the given actions

  • :param (String)

    overrides the default param name of :id in the URL

Raises:

  • (ArgumentError)


341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/rage/router/dsl.rb', line 341

def resources(*_resources, **opts, &block)
  # support calls with multiple resources, e.g. `resources :albums, :photos`
  if _resources.length > 1
    _resources.each { |_resource| resources(_resource, **opts, &block) }
    return
  end

  _module, _path, _only, _except, _param = opts.values_at(:module, :path, :only, :except, :param)
  raise ArgumentError, ":param option can't contain colons" if _param.to_s.include?(":")

  _only = Array(_only) if _only
  _except = Array(_except) if _except
  actions = @default_actions.select do |action|
    (_only.nil? || _only.include?(action)) && (_except.nil? || !_except.include?(action))
  end

  resource = _resources[0].to_s
  _path ||= resource
  _param ||= "id"

  scope_opts = { path: _path }
  scope_opts[:module] = _module if _module

  scope(scope_opts) do
    get("/", to: "#{resource}#index") if actions.include?(:index)
    post("/", to: "#{resource}#create") if actions.include?(:create)
    get("/:#{_param}", to: "#{resource}#show") if actions.include?(:show)
    patch("/:#{_param}", to: "#{resource}#update") if actions.include?(:update)
    put("/:#{_param}", to: "#{resource}#update") if actions.include?(:update)
    delete("/:#{_param}", to: "#{resource}#destroy") if actions.include?(:destroy)

    scope(path: ":#{to_singular(resource)}_#{_param}", controller: resource, &block) if block
  end
end

#root(to:) ⇒ Object

Register a new route pointing to '/'.

Examples:

root to: "photos#index"

Parameters:

  • to (String)

    the route handler in the format of "controller#action"



154
155
156
# File 'lib/rage/router/dsl.rb', line 154

def root(to:)
  __on("GET", "/", to, nil, nil)
end

#scope(opts, &block) ⇒ Object

Scopes a set of routes to the given default options.

Examples:

Route /photos to Api::PhotosController

scope module: "api" do
  get "photos", to: "photos#index"
end

Route admin/photos to PhotosController

scope path: "admin" do
  get "photos", to: "photos#index"
end

Route /like to photos#like and /dislike to photos#dislike

scope controller: "photos" do
  post "like"
  post "dislike"
end

Nested calls

scope module: "admin" do
  get "photos", to: "photos#index"

  scope path: "api", module: "api" do
    get "photos/:id", to: "photos#show"
  end
end

Parameters:

  • opts (Hash)

    scope options.

Options Hash (opts):

  • :module (String)

    the namespace for the controller

  • :path (String)

    the path prefix for the routes

  • :controller (String)

    scopes routes to a specific controller

Raises:

  • (ArgumentError)


249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/rage/router/dsl.rb', line 249

def scope(opts, &block)
  raise ArgumentError, "only :module, :path, and :controller options are accepted" if (opts.keys - @scope_opts).any?

  @path_prefixes << opts[:path].delete_prefix("/").delete_suffix("/") if opts[:path]
  @module_prefixes << opts[:module] if opts[:module]
  @controllers << opts[:controller] if opts[:controller]

  instance_eval(&block)

  @path_prefixes.pop if opts[:path]
  @module_prefixes.pop if opts[:module]
  @controllers.pop if opts[:controller]
end