class Rage::Router::DSL::Handler
end
resources :posts
namespace :admin do
@example Scope routes to a specific namespace.
end
resources :projects
scope path: “:account_id” do
@example Scope a set of routes to the given default options.
end
resources :ads
resources :magazines do
@example Set up multiple resources
root to: “pages#main”
@example Set up a root handler
Parameter constraints are likely to be added in the future versions. Custom/lambda constraints are unlikely to be ever added.
“‘
get “/photos”, to: “photos#index”, constraints: { host: “myhost.com” }
“`ruby
Example:
Currently, the only constraint supported is the `host` constraint. The constraint value can be either string or a regular expression.
#### Constraints
Also, as this is an API-only framework, route helpers, like `photos_path` or `photos_url` are not being generated.
“`
get “/photos/*”
“`ruby
Example:
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.
This class implements routing logic for your application, providing an API similar to Rails.
#
def __on(method, path, to, constraints, defaults)
def __on(method, path, to, constraints, defaults) # handle calls without controller inside resources: # resources :comments do # post :like # end if !to if @controllers.any? to = "#{@controllers.last}##{path}" else raise ArgumentError, "Missing :to key on routes definition, please check your routes." end end # process path to ensure it starts with "/" and doesn't end with "/" if path != "/" path = "/#{path}" unless path.start_with?("/") path = path.delete_suffix("/") if path.end_with?("/") end # correctly process root helpers inside `scope` calls if path == "/" && @path_prefixes.any? path = "" end path_prefix = @path_prefixes.any? ? "/#{@path_prefixes.join("/")}" : nil module_prefix = @module_prefixes.any? ? "#{@module_prefixes.join("/")}/" : nil defaults = (defaults ? @defaults + [defaults] : @defaults).reduce(&:merge) if to.is_a?(String) @router.on(method, "#{path_prefix}#{path}", "#{module_prefix}#{to}", constraints: constraints || {}, defaults: defaults) else @router.on(method, "#{path_prefix}#{path}", to, constraints: constraints || {}, defaults: defaults) end end
def __with_on_scope(on, &block)
def __with_on_scope(on, &block) case on when nil block.call when :member member(&block) when :collection collection(&block) else raise ArgumentError, "Unknown scope :#{on} given to :on" end end
def collection(&block)
- Example: Add a `photos/search` path instead of `photos/:photo_id/search` -
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
def controller(controller, &block)
post "dislike"
post "like"
controller "photos" do
@example
Scopes routes to a specific controller.
def controller(controller, &block) @controllers << controller instance_eval(&block) @controllers.pop end
def defaults(defaults, &block)
-
defaults(Hash) -- a hash of default parameters
def defaults(defaults, &block) @defaults << defaults instance_eval(&block) @defaults.pop end
def delete(path, to: nil, constraints: nil, defaults: nil, on: nil)
-
on(nil, :member, :collection) -- a shorthand for wrapping routes in a specific RESTful context -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String) -- the route handler in the format of "controller#action" -
path(String) -- the path for the route handler
def delete(path, to: nil, constraints: nil, defaults: nil, on: nil) __with_on_scope(on) { __on("DELETE", path, to, constraints, defaults) } end
def get(path, to: nil, constraints: nil, defaults: nil, on: nil)
-
on(nil, :member, :collection) -- a shorthand for wrapping routes in a specific RESTful context -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String) -- the route handler in the format of "controller#action" -
path(String) -- the path for the route handler
def get(path, to: nil, constraints: nil, defaults: nil, on: nil) __with_on_scope(on) { __on("GET", path, to, constraints, defaults) } end
def initialize(router)
- Private: -
def initialize(router) @router = router @default_actions = %i(index create show update destroy) @default_match_methods = %i(get post put patch delete head) @scope_opts = %i(module path controller) @path_prefixes = [] @module_prefixes = [] @defaults = [] @controllers = [] end
def match(path, to:, constraints: {}, defaults: nil, via: :all)
-
via(Symbol, Array) -- an array of HTTP methods to accept -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String, #call) -- the route handler in the format of "controller#action" or a callable -
path(String) -- the path for the route handler
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
def member(&block)
- Example: Add a `photos/:id/preview` path instead of `photos/:photo_id/preview` -
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
def mount(app, at:, via: :all)
@example
mount Sidekiq::Web => "/sidekiq"
@example
Mount a Rack-based application to be used within the application.
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
def namespace(path, **options, &block)
(**options)-
:path(String) -- the path for the namespace -
:module(String) -- the module name for the namespace
Parameters:
-
options(Hash) -- a hash of options for the namespace -
path(String) -- the path for the namespace
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
def patch(path, to: nil, constraints: nil, defaults: nil, on: nil)
-
on(nil, :member, :collection) -- a shorthand for wrapping routes in a specific RESTful context -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String) -- the route handler in the format of "controller#action" -
path(String) -- the path for the route handler
def patch(path, to: nil, constraints: nil, defaults: nil, on: nil) __with_on_scope(on) { __on("PATCH", path, to, constraints, defaults) } end
def post(path, to: nil, constraints: nil, defaults: nil, on: nil)
-
on(nil, :member, :collection) -- a shorthand for wrapping routes in a specific RESTful context -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String) -- the route handler in the format of "controller#action" -
path(String) -- the path for the route handler
def post(path, to: nil, constraints: nil, defaults: nil, on: nil) __with_on_scope(on) { __on("POST", path, to, constraints, defaults) } end
def put(path, to: nil, constraints: nil, defaults: nil, on: nil)
-
on(nil, :member, :collection) -- a shorthand for wrapping routes in a specific RESTful context -
defaults(Hash) -- a hash of default parameters for the route -
constraints(Hash) -- a hash of constraints for the route -
to(String) -- the route handler in the format of "controller#action" -
path(String) -- the path for the route handler
def put(path, to: nil, constraints: nil, defaults: nil, on: nil) __with_on_scope(on) { __on("PUT", path, to, constraints, defaults) } end
def resources(*_resources, **opts, &block)
- Note: - This helper doesn't generate the `new` and `edit` routes.
Other tags:
- Example: Create five REST routes, all mapping to the `Photos` controller: -
Options Hash:
(**opts)-
:param(String) -- overrides the default param name of `:id` in the URL -
:except(Symbol, Array) -- generate all routes except for the given actions -
:only(Symbol, Array) -- only generate routes for the given actions -
:path(String) -- the path prefix for the routes -
:module(String) -- the namespace for the controller
Parameters:
-
opts(Hash) -- resource options
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
def root(to:)
-
to(String) -- the route handler in the format of "controller#action"
def root(to:) __on("GET", "/", to, nil, nil) end
def scope(opts, &block)
- Example: Nested calls -
Example: Route `/like` to `photos#like` and `/dislike` to `photos#dislike` -
Example: Route `admin/photos` to `PhotosController` -
Example: Route `/photos` to `Api::PhotosController` -
Options Hash:
(**opts)-
:controller(String) -- scopes routes to a specific controller -
:path(String) -- the path prefix for the routes -
:module(String) -- the namespace for the controller
Parameters:
-
opts(Hash) -- scope options.
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
def to_singular(str)
def to_singular(str) @active_support_loaded ||= str.respond_to?(:singularize) || :false return str.singularize if @active_support_loaded != :false @endings ||= { "ves" => "fe", "ies" => "y", "i" => "us", "zes" => "ze", "ses" => "s", "es" => "", "s" => "" } @regexp ||= Regexp.new("(#{@endings.keys.join("|")})$") str.sub(@regexp, @endings) end