class RailsAiAdmin::Queries::NamedScope
A declared list tab. It can only narrow the current authorized relation: its body builds a separate candidate relation whose primary keys are then intersected with the policy scope, so ‘unscoped`, `or` or a replaced condition inside the body cannot widen the result.
Constants
Attributes
Public Class Methods
Source
# File lib/rails_ai_admin/queries/named_scope.rb, line 18 def initialize(name, body = nil, label: nil, default: false) unless (name.is_a?(String) || name.is_a?(Symbol)) && name.to_s.match?(NAME) raise ConfigurationError, "Named scope needs a lowercase identifier of at most 40 characters" end unless body.nil? || body.is_a?(Proc) && body.lambda? && body.arity.zero? raise ConfigurationError, "Named scope body must be a zero-argument lambda" end raise ConfigurationError, "Named scope default must be boolean" unless [ true, false ].include?(default) @name = name.to_sym @label = Navigation::Settings.caption(label) || Navigation::Settings.caption(@name.to_s.humanize) @body = body @default = default freeze end
Public Instance Methods
Source
# File lib/rails_ai_admin/queries/named_scope.rb, line 37 def apply(relation) return relation if body.nil? model = relation.klass primary_key = model.primary_key raise ConfigurationError, "Named scopes require a single-column primary key" unless primary_key.is_a?(String) candidate = build(model) unless candidate.is_a?(ActiveRecord::Relation) && candidate.klass == model raise ConfigurationError, "Named scope #{name} must return the resource's ActiveRecord relation" end if candidate.limit_value || candidate.offset_value || candidate.select_values.any? || candidate.group_values.any? || !candidate.having_clause.empty? || !candidate.from_clause.empty? || candidate.includes_values.any? || candidate.eager_load_values.any? || candidate.preload_values.any? raise ConfigurationError, "Named scope #{name} must be a filter relation without limit, offset, select, group, having, from or eager loading" end relation.where(primary_key => candidate.unscope(:order).select(model.arel_table[primary_key])) end
Returns the policy relation narrowed to this scope. Trusted host Ruby still runs here; writes are prevented and failures stay generic.
Source
# File lib/rails_ai_admin/queries/named_scope.rb, line 56 def build(model) ActiveRecord::Base.while_preventing_writes { model.all.instance_exec(&body) } rescue ConfigurationError raise rescue StandardError raise ConfigurationError, "Named scope #{name} failed", cause: nil end
Source
# File lib/rails_ai_admin/queries/named_scope.rb, line 33 def default? = @default # Returns the policy relation narrowed to this scope. Trusted host Ruby # still runs here; writes are prevented and failures stay generic. def apply(relation) return relation if body.nil? model = relation.klass primary_key = model.primary_key raise ConfigurationError, "Named scopes require a single-column primary key" unless primary_key.is_a?(String) candidate = build(model) unless candidate.is_a?(ActiveRecord::Relation) && candidate.klass == model raise ConfigurationError, "Named scope #{name} must return the resource's ActiveRecord relation" end if candidate.limit_value || candidate.offset_value || candidate.select_values.any? || candidate.group_values.any? || !candidate.having_clause.empty? || !candidate.from_clause.empty? || candidate.includes_values.any? || candidate.eager_load_values.any? || candidate.preload_values.any? raise ConfigurationError, "Named scope #{name} must be a filter relation without limit, offset, select, group, having, from or eager loading" end relation.where(primary_key => candidate.unscope(:order).select(model.arel_table[primary_key])) end private def build(model) ActiveRecord::Base.while_preventing_writes { model.all.instance_exec(&body) } rescue ConfigurationError raise rescue StandardError raise ConfigurationError, "Named scope #{name} failed", cause: nil end end