Module: Rhino

Defined in:
lib/rhino.rb,
lib/rhino/query.rb,
lib/rhino/engine.rb,
lib/rhino/routes.rb,
lib/rhino/context.rb,
lib/rhino/railtie.rb,
lib/rhino/version.rb,
lib/rhino/auth_hooks.rb,
lib/rhino/scope_spec.rb,
lib/rhino/auth_rejected.rb,
lib/rhino/configuration.rb,
lib/rhino/query_builder.rb,
lib/rhino/resource_scope.rb,
lib/rhino/argument_binder.rb,
lib/rhino/blueprint/sorter.rb,
lib/rhino/group_membership.rb,
lib/rhino/models/audit_log.rb,
lib/rhino/resource_request.rb,
lib/rhino/concerns/has_uuid.rb,
lib/rhino/concerns/has_rhino.rb,
lib/rhino/models/rhino_model.rb,
lib/rhino/configuration_error.rb,
lib/rhino/permissions_migrator.rb,
lib/rhino/commands/base_command.rb,
lib/rhino/missing_tenant_context.rb,
lib/rhino/scopes_to_organization.rb,
lib/rhino/computed_attribute_spec.rb,
lib/rhino/concerns/has_auto_scope.rb,
lib/rhino/concerns/has_validation.rb,
lib/rhino/scope_not_allowed_error.rb,
lib/rhino/commands/install_command.rb,
lib/rhino/concerns/has_audit_trail.rb,
lib/rhino/concerns/has_permissions.rb,
lib/rhino/concerns/hidable_columns.rb,
lib/rhino/policies/resource_policy.rb,
lib/rhino/commands/generate_command.rb,
lib/rhino/mailers/invitation_mailer.rb,
lib/rhino/routing/domain_constraint.rb,
lib/rhino/blueprint/blueprint_parser.rb,
lib/rhino/blueprint/manifest_manager.rb,
lib/rhino/commands/blueprint_command.rb,
lib/rhino/policies/invitation_policy.rb,
lib/rhino/controllers/auth_controller.rb,
lib/rhino/concerns/route_group_context.rb,
lib/rhino/blueprint/blueprint_validator.rb,
lib/rhino/commands/export_types_command.rb,
lib/rhino/invalid_scope_arguments_error.rb,
lib/rhino/routing/route_group_validator.rb,
lib/rhino/models/organization_invitation.rb,
lib/rhino/commands/export_postman_command.rb,
lib/rhino/commands/invitation_link_command.rb,
lib/rhino/concerns/belongs_to_organization.rb,
lib/rhino/controllers/resources_controller.rb,
lib/rhino/controllers/invitations_controller.rb,
lib/rhino/blueprint/generators/test_generator.rb,
lib/rhino/blueprint/generators/policy_generator.rb,
lib/rhino/blueprint/generators/seeder_generator.rb,
lib/rhino/blueprint/generators/factory_generator.rb,
lib/rhino/invalid_computed_attribute_arguments_error.rb,
lib/rhino/middleware/resolve_organization_from_route.rb

Defined Under Namespace

Modules: ArgumentBinder, BelongsToOrganization, Blueprint, Commands, ComputedAttributeSpec, Context, GroupMembership, HasAuditTrail, HasAutoScope, HasPermissions, HasRhino, HasUuid, HasValidation, HidableColumns, Middleware, RouteGroupContext, Routes, Routing, ScopeSpec, ScopesToOrganization Classes: AuditLog, AuthController, AuthHooks, AuthRejected, Configuration, ConfigurationError, Engine, InvalidComputedAttributeArgumentsError, InvalidScopeArgumentsError, InvitationMailer, InvitationPolicy, InvitationsController, MissingTenantContext, OrganizationInvitation, PendingScopedContext, PermissionsMigrator, QueryAttributeNotAllowedError, QueryBuilder, Railtie, ResourcePolicy, ResourceRequest, ResourceScope, ResourcesController, RhinoModel, RouteGroupConflictError, ScopeNotAllowedError

Constant Summary collapse

VERSION =
"4.10.0"

Class Method Summary collapse

Class Method Details

.apply_named_scope(relation, model_class, scope_name = nil, *args) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Apply a whitelisted named scope to relation for model_class. Shared by Rhino.scoped_query and PendingScopedContext#scoped_query. Uses the same allowed_scopes / default_rhino_scope mechanism as the QueryBuilder.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rhino/query.rb', line 80

def apply_named_scope(relation, model_class, scope_name = nil, *args)
  requested = scope_name.to_s.presence
  name = requested ? requested.underscore : model_class.try(:default_rhino_scope)
  return relation unless name

  allowed = Rhino::ScopeSpec.normalize(model_class.try(:allowed_scopes))
  entry = allowed[name]
  entry ||= { target: name.to_sym, params: [], optional: [] } if name == model_class.try(:default_rhino_scope)

  raise Rhino::ScopeNotAllowedError, (requested || name) if entry.nil?

  user = defined?(RequestStore) ? RequestStore.store[:rhino_current_user] : nil
  target = entry[:target] || name.to_sym

  # Server-side caller: the policy gate belongs to the request path, and any
  # arguments here come from application code, not from a client.
  case target
  when Symbol, String
    relation.merge(model_class.public_send(target, *args))
  when Proc
    target.call(relation, user, *args)
  else
    target.new.apply(relation, *args)
  end
end

.configuration ⇒ Object Also known as: config



33
34
35
# File 'lib/rhino.rb', line 33

def configuration
  @configuration ||= Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Yields:



29
30
31
# File 'lib/rhino.rb', line 29

def configure
  yield(configuration)
end

.context ⇒ Object

The ambient context resolver.



72
73
74
# File 'lib/rhino/query.rb', line 72

def context
  Rhino::Context
end

.for_user(user) ⇒ Object

Begin the fluent explicit builder for user.



53
54
55
# File 'lib/rhino/query.rb', line 53

def for_user(user)
  Rhino::PendingScopedContext.new(user: user)
end

.in_route_group(route_group) ⇒ Object

Begin an explicit context that acts as the named route group, for use where no request resolves one — an Active Job, a rake task, the console, a test.

The group's own configuration still decides the boundary: naming a group declared tenant: false lets the query span every organization, while naming any other group keeps failing closed.

Rhino.in_route_group(:admin).query(Task)
Rhino.for_user(user).in_route_group(:admin).run { ... }


67
68
69
# File 'lib/rhino/query.rb', line 67

def in_route_group(route_group)
  Rhino::PendingScopedContext.new(user: nil, route_group: route_group)
end

.query(model_class) ⇒ Object

Build a tenant-scoped relation for model_class using the ambient context.

Applies the same org scoping as CRUD plus the model's default_scopes (BelongsToOrganization / HasAutoScope read RequestStore at BUILD time).

Fail closed: an org-scopable model with no org context RAISES Rhino::MissingTenantContext rather than returning an unscoped relation — unless the query belongs to a route group declared non-tenant (tenant: false), either because the request is served by that group or because the caller said so with Rhino.in_route_group(...). An explicit organization is always honored, in every group.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rhino/query.rb', line 28

def query(model_class)
  org = Rhino::Context.organization

  # default_scope (org via RequestStore) + auto-scope are baked here at build.
  relation = model_class.all

  if Rhino::ScopesToOrganization.organization_scoped?(model_class)
    if org
      relation = Rhino::ScopesToOrganization.scope_to_organization(relation, model_class, org, strict: true)
    elsif Rhino.config.group_tenant?(Rhino::Context.route_group)
      raise Rhino::MissingTenantContext, model_class.name
    end
  end

  relation
end

.reset_configuration! ⇒ Object



39
40
41
# File 'lib/rhino.rb', line 39

def reset_configuration!
  @configuration = Configuration.new
end

.scoped_query(model_class, scope_name = nil, *args) ⇒ Object

Build a tenant-scoped relation and apply a whitelisted ?scope= named scope on top of it. scope_name is the wire name (camelCase accepted); nil falls back to the model's rhino_default_scope.



48
49
50
# File 'lib/rhino/query.rb', line 48

def scoped_query(model_class, scope_name = nil, *args)
  apply_named_scope(query(model_class), model_class, scope_name, *args)
end