Module: Organizations::OrganizationScoped

Extended by:
ActiveSupport::Concern
Includes:
CurrentUserResolution
Defined in:
lib/organizations/organization_scoped.rb

Overview

URL-SCOPED organization resolution — the second addressing mode.

The engine's own controllers are SESSION-scoped (one "current" organization per user, workspace/tenant style — the LicenseSeat shape). Overlay-style hosts (community/marketplace apps where users belong to organizations but don't "work inside" one) address organizations BY URL instead: /org/:slug/admin, /teams/:id/settings. Before this concern, such hosts re-derived the same base controller by hand: find org by param → find viewer membership → role-gate → pick a not-found posture.

Knobs (class_attributes, inheritable/overridable per controller):

organization_param    — request param holding the identifier
                      (default :organization_id)
organization_finder   — ->(param) { ... } returning the org or nil;
                      instance_exec'd on the controller (default
                      find_by(id:))
organization_not_found_behavior — :not_found (default) raises
                      ActionController::RoutingError so unknown orgs,
                      non-members, and under-role members are all
                      INDISTINGUISHABLE (no existence oracle);
                      :forbidden responds 403 instead (internal
                      tools where disclosure is fine).

Deliberately DISTINCT from the session helpers (current_organization/ current_membership): the two modes coexist — a session-tenant app can still expose a URL-scoped surface — so this concern never touches the session or the model-level current-organization context.

Examples:

A slug-addressed admin portal (the overlay shape)

class Portal::BaseController < ApplicationController
  include Organizations::OrganizationScoped

  self.organization_param  = :slug
  self.organization_finder = ->(param) { Organizations::Organization.find_by(slug: param) }
  # 404-never-403: don't disclose which orgs/surfaces exist (default).
  require_organization_role :admin
end

class Portal::MembersController < Portal::BaseController
  def index
    @memberships = current_scoped_organization.memberships.includes(:user)
  end
end

Instance Method Summary collapse

Instance Method Details

#current_scoped_membershipOrganizations::Membership?

The requesting user's membership in the scoped organization. Memoized per request; nil for strangers/signed-out.

Returns:



88
89
90
91
92
93
94
# File 'lib/organizations/organization_scoped.rb', line 88

def current_scoped_membership
  return @current_scoped_membership if defined?(@current_scoped_membership)

  user = scoped_organization_viewer
  @current_scoped_membership =
    (current_scoped_organization.memberships.find_by(user_id: user.id) if user && current_scoped_organization)
end

#current_scoped_organizationOrganizations::Organization?

The organization resolved from the URL for this request.

Returns:



81
82
83
# File 'lib/organizations/organization_scoped.rb', line 81

def current_scoped_organization
  @current_scoped_organization
end