Class: Rhino::Routing::DomainConstraint

Inherits:
Object
  • Object
show all
Defined in:
lib/rhino/routing/domain_constraint.rb

Overview

Rails route constraint that restricts a route group’s routes to a specific host/domain. Mirrors Laravel’s Route::domain() behavior.

The domain pattern may be:

- A literal host, e.g. "admin.example.com" — matches only that host.
- A parameterized host, e.g. "{organization}.example.com" — matches that
  pattern and captures the "{organization}" segment. The captured value
  is injected into request.path_parameters so it surfaces as
  params[:organization] — exactly like the path-prefix ":organization"
  does. The controller's `before_action :resolve_organization` then reads
  params[:organization] (after routing has populated path parameters) to
  resolve the tenant, enabling subdomain multitenancy.

Usage (in routes):

constraints(Rhino::Routing::DomainConstraint.new("{organization}.example.com")) do
  # ... routes ...
end

Constant Summary collapse

PLACEHOLDER =

Matches a “name” placeholder in the domain pattern.

/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pattern) ⇒ DomainConstraint

Returns a new instance of DomainConstraint.



28
29
30
31
32
# File 'lib/rhino/routing/domain_constraint.rb', line 28

def initialize(pattern)
  @pattern = pattern.to_s
  @param_names = []
  @regexp = compile(@pattern)
end

Instance Attribute Details

#param_namesObject (readonly)

Returns the value of attribute param_names.



26
27
28
# File 'lib/rhino/routing/domain_constraint.rb', line 26

def param_names
  @param_names
end

#patternObject (readonly)

Returns the value of attribute pattern.



26
27
28
# File 'lib/rhino/routing/domain_constraint.rb', line 26

def pattern
  @pattern
end

#regexpObject (readonly)

Returns the value of attribute regexp.



26
27
28
# File 'lib/rhino/routing/domain_constraint.rb', line 26

def regexp
  @regexp
end

Instance Method Details

#matches?(request) ⇒ Boolean

Rails calls this for each request when the constraint is attached to a scope. Returns true iff the request host matches the compiled pattern. As a side effect, for parameterized domains the captured values are injected into the request’s path parameters so the controller’s ‘before_action :resolve_organization` can read them as params.

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rhino/routing/domain_constraint.rb', line 44

def matches?(request)
  # Hosts are case-insensitive (DNS), so normalize before matching. This
  # ensures captured values (e.g. the "{organization}" subdomain) are
  # lowercased, matching how org slugs are stored — a mixed-case host like
  # "ORG-ONE.example.com" resolves the "org-one" organization.
  host = request.host.to_s.downcase
  match = @regexp.match(host)
  return false unless match

  inject_path_parameters(request, match) if parameterized?

  true
end

#parameterized?Boolean

Whether this constraint carries dynamic captures (parameterized domain).

Returns:

  • (Boolean)


35
36
37
# File 'lib/rhino/routing/domain_constraint.rb', line 35

def parameterized?
  @param_names.any?
end