Class: Heimdallr::Proxy::Collection
- Inherits:
-
Object
- Object
- Heimdallr::Proxy::Collection
- Includes:
- Enumerable
- Defined in:
- lib/heimdallr/proxy/collection.rb
Overview
A security-aware proxy for ActiveRecord
scopes. This class validates all the method calls and either forwards them to the encapsulated scope or raises an exception.
There are two kinds of collection proxies, explicit and implicit, which instantiate the corresponding types of record proxies. See also Record.
Instance Method Summary collapse
-
#all ⇒ Object
A proxy for
all
method which returns an array of restricted records. -
#any? ⇒ Object
A proxy for
any?
method which returns a raw value. -
#average ⇒ Object
A proxy for
average
method which returns a raw value. -
#build ⇒ Object
A proxy for
build
method which adds fixtures to the attribute list and returns a restricted record. -
#calculate ⇒ Object
A proxy for
calculate
method which returns a raw value. -
#count ⇒ Object
A proxy for
count
method which returns a raw value. - #creatable? ⇒ Boolean
-
#create ⇒ Object
A proxy for
create
method which adds fixtures to the attribute list and returns a restricted record. -
#create! ⇒ Object
A proxy for
create!
method which adds fixtures to the attribute list and returns a restricted record. -
#delete ⇒ Object
A proxy for
delete
method which works on a:delete
scope. -
#delete_all ⇒ Object
A proxy for
delete_all
method which works on a:delete
scope. -
#destroy ⇒ Object
A proxy for
destroy
method which works on a:delete
scope. -
#destroy_all ⇒ Object
A proxy for
destroy_all
method which works on a:delete
scope. -
#each {|record| ... } ⇒ Object
A proxy for
each
which restricts the yielded records. -
#empty? ⇒ Object
A proxy for
empty?
method which returns a raw value. -
#exists? ⇒ Object
A proxy for
exists?
method which returns a raw value. -
#extending ⇒ Object
A proxy for
extending
method which returns a restricted scope. -
#find(*args) ⇒ Proxy::Record+
A proxy for
find
which restricts the returned record or records. -
#first ⇒ Object
A proxy for
first
method which returns a restricted record. -
#first! ⇒ Object
A proxy for
first!
method which returns a restricted record. -
#include? ⇒ Object
A proxy for
include?
method which returns a raw value. -
#includes(*associations) ⇒ Object
A proxy for
includes
which adds Heimdallr conditions for eager loaded associations. -
#initialize(context, scope, options = {}) ⇒ Collection
constructor
Create a collection proxy.
-
#insecure ⇒ Object
Return the underlying scope.
-
#inspect ⇒ String
Describes the proxy and proxified scope.
-
#joins ⇒ Object
A proxy for
joins
method which returns a restricted scope. -
#last ⇒ Object
A proxy for
last
method which returns a restricted record. -
#last! ⇒ Object
A proxy for
last!
method which returns a restricted record. -
#length ⇒ Object
A proxy for
length
method which returns a raw value. -
#limit ⇒ Object
A proxy for
limit
method which returns a restricted scope. -
#lock ⇒ Object
A proxy for
lock
method which returns a restricted scope. -
#many? ⇒ Object
A proxy for
many?
method which returns a raw value. -
#maximum ⇒ Object
A proxy for
maximum
method which returns a raw value. -
#method_missing(method, *args) ⇒ Object
Wraps a scope or a record in a corresponding proxy.
-
#minimum ⇒ Object
A proxy for
minimum
method which returns a raw value. -
#new ⇒ Object
A proxy for
new
method which adds fixtures to the attribute list and returns a restricted record. -
#offset ⇒ Object
A proxy for
offset
method which returns a restricted scope. -
#order ⇒ Object
A proxy for
order
method which returns a restricted scope. -
#pluck ⇒ Object
A proxy for
pluck
method which returns a raw value. -
#reflect_on_security ⇒ Hash
Return the associated security metadata.
-
#reorder ⇒ Object
A proxy for
reorder
method which returns a restricted scope. -
#restrict(context, options = nil) ⇒ Object
Collections cannot be restricted with different context or options.
-
#reverse_order ⇒ Object
A proxy for
reverse_order
method which returns a restricted scope. -
#scoped ⇒ Object
A proxy for
scoped
method which returns a restricted scope. -
#size ⇒ Object
A proxy for
size
method which returns a raw value. -
#sum ⇒ Object
A proxy for
sum
method which returns a raw value. -
#to_a ⇒ Object
A proxy for
to_a
method which returns an array of restricted records. -
#to_ary ⇒ Object
A proxy for
to_ary
method which returns an array of restricted records. -
#uniq ⇒ Object
A proxy for
uniq
method which returns a restricted scope. -
#where ⇒ Object
A proxy for
where
method which returns a restricted scope.
Constructor Details
#initialize(context, scope, options = {}) ⇒ Collection
Create a collection proxy.
The scope
is expected to be already restricted with :fetch
scope.
18 19 20 21 22 23 |
# File 'lib/heimdallr/proxy/collection.rb', line 18 def initialize(context, scope, ={}) @context, @scope, = context, scope, @restrictions = @scope.restrictions(context) [:eager_loaded] ||= {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
Wraps a scope or a record in a corresponding proxy.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/heimdallr/proxy/collection.rb', line 232 def method_missing(method, *args) if method =~ /^find_all_by/ @scope.send(method, *args).map do |element| element.restrict(@context, ) end elsif method =~ /^find_by/ @scope.send(method, *args).restrict(@context, ) elsif @scope.heimdallr_scopes && @scope.heimdallr_scopes.include?(method) Proxy::Collection.new(@context, @scope.send(method, *args), ) elsif @scope.respond_to? method raise InsecureOperationError, "Potentially insecure method #{method} was called" else super end end |
Instance Method Details
#all ⇒ Object
A proxy for all
method which returns an array of restricted records.
151 |
# File 'lib/heimdallr/proxy/collection.rb', line 151 delegate_as_records :all |
#any? ⇒ Object
A proxy for any?
method which returns a raw value.
126 |
# File 'lib/heimdallr/proxy/collection.rb', line 126 delegate_as_value :any? |
#average ⇒ Object
A proxy for average
method which returns a raw value.
135 |
# File 'lib/heimdallr/proxy/collection.rb', line 135 delegate_as_value :average |
#build ⇒ Object
A proxy for build
method which adds fixtures to the attribute list and returns a restricted record.
108 |
# File 'lib/heimdallr/proxy/collection.rb', line 108 delegate_as_constructor :build, :assign_attributes |
#calculate ⇒ Object
A proxy for calculate
method which returns a raw value.
133 |
# File 'lib/heimdallr/proxy/collection.rb', line 133 delegate_as_value :calculate |
#count ⇒ Object
A proxy for count
method which returns a raw value.
134 |
# File 'lib/heimdallr/proxy/collection.rb', line 134 delegate_as_value :count |
#creatable? ⇒ Boolean
281 282 283 |
# File 'lib/heimdallr/proxy/collection.rb', line 281 def creatable? @restrictions.can? :create end |
#create ⇒ Object
A proxy for create
method which adds fixtures to the attribute list and returns a restricted record.
110 |
# File 'lib/heimdallr/proxy/collection.rb', line 110 delegate_as_constructor :create, :update_attributes |
#create! ⇒ Object
A proxy for create!
method which adds fixtures to the attribute list and returns a restricted record.
111 |
# File 'lib/heimdallr/proxy/collection.rb', line 111 delegate_as_constructor :create!, :update_attributes! |
#delete ⇒ Object
A proxy for delete
method which works on a :delete
scope.
141 |
# File 'lib/heimdallr/proxy/collection.rb', line 141 delegate_as_destroyer :delete |
#delete_all ⇒ Object
A proxy for delete_all
method which works on a :delete
scope.
142 |
# File 'lib/heimdallr/proxy/collection.rb', line 142 delegate_as_destroyer :delete_all |
#destroy ⇒ Object
A proxy for destroy
method which works on a :delete
scope.
143 |
# File 'lib/heimdallr/proxy/collection.rb', line 143 delegate_as_destroyer :destroy |
#destroy_all ⇒ Object
A proxy for destroy_all
method which works on a :delete
scope.
144 |
# File 'lib/heimdallr/proxy/collection.rb', line 144 delegate_as_destroyer :destroy_all |
#each {|record| ... } ⇒ Object
A proxy for each
which restricts the yielded records.
225 226 227 228 229 |
# File 'lib/heimdallr/proxy/collection.rb', line 225 def each @scope.each do |record| yield record.restrict(@context, ) end end |
#empty? ⇒ Object
A proxy for empty?
method which returns a raw value.
125 |
# File 'lib/heimdallr/proxy/collection.rb', line 125 delegate_as_value :empty? |
#exists? ⇒ Object
A proxy for exists?
method which returns a raw value.
129 |
# File 'lib/heimdallr/proxy/collection.rb', line 129 delegate_as_value :exists? |
#extending ⇒ Object
A proxy for extending
method which returns a restricted scope.
123 |
# File 'lib/heimdallr/proxy/collection.rb', line 123 delegate_as_scope :extending |
#find(*args) ⇒ Proxy::Record+
A proxy for find
which restricts the returned record or records.
209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/heimdallr/proxy/collection.rb', line 209 def find(*args) result = @scope.find(*args) if result.is_a? Enumerable result.map do |element| element.restrict(@context, ) end else result.restrict(@context, ) end end |
#first ⇒ Object
A proxy for first
method which returns a restricted record.
146 |
# File 'lib/heimdallr/proxy/collection.rb', line 146 delegate_as_record :first |
#first! ⇒ Object
A proxy for first!
method which returns a restricted record.
147 |
# File 'lib/heimdallr/proxy/collection.rb', line 147 delegate_as_record :first! |
#include? ⇒ Object
A proxy for include?
method which returns a raw value.
128 |
# File 'lib/heimdallr/proxy/collection.rb', line 128 delegate_as_value :include? |
#includes(*associations) ⇒ Object
A proxy for includes
which adds Heimdallr conditions for eager loaded associations.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/heimdallr/proxy/collection.rb', line 157 def includes(*associations) # Normalize association list to strict nested hash. normalize = ->(list) { if list.is_a? Array list.map(&normalize).reduce(:merge) elsif list.is_a? Symbol { list => {} } elsif list.is_a? Hash hash = {} list.each do |key, value| hash[key] = normalize.(value) end hash end } associations = normalize.(associations) current_scope = @scope.includes(associations) add_conditions = ->(associations, scope) { associations.each do |association, nested| reflection = scope.reflect_on_association(association) if reflection && !reflection.[:polymorphic] associated_klass = reflection.klass if associated_klass.respond_to? :restrict nested_scope = associated_klass.restrictions(@context).request_scope(:fetch) where_values = nested_scope.where_values if where_values.any? current_scope = current_scope.where(*where_values) end add_conditions.(nested, associated_klass) end end end } unless Heimdallr.skip_eager_condition_injection add_conditions.(associations, current_scope) end = .merge(eager_loaded: [:eager_loaded].merge(associations)) Proxy::Collection.new(@context, current_scope, ) end |
#insecure ⇒ Object
Return the underlying scope.
252 253 254 |
# File 'lib/heimdallr/proxy/collection.rb', line 252 def insecure @scope end |
#inspect ⇒ String
Describes the proxy and proxified scope.
259 260 261 |
# File 'lib/heimdallr/proxy/collection.rb', line 259 def inspect "#<Heimdallr::Proxy::Collection: #{@scope.to_sql}>" end |
#joins ⇒ Object
A proxy for joins
method which returns a restricted scope.
116 |
# File 'lib/heimdallr/proxy/collection.rb', line 116 delegate_as_scope :joins |
#last ⇒ Object
A proxy for last
method which returns a restricted record.
148 |
# File 'lib/heimdallr/proxy/collection.rb', line 148 delegate_as_record :last |
#last! ⇒ Object
A proxy for last!
method which returns a restricted record.
149 |
# File 'lib/heimdallr/proxy/collection.rb', line 149 delegate_as_record :last! |
#length ⇒ Object
A proxy for length
method which returns a raw value.
131 |
# File 'lib/heimdallr/proxy/collection.rb', line 131 delegate_as_value :length |
#limit ⇒ Object
A proxy for limit
method which returns a restricted scope.
118 |
# File 'lib/heimdallr/proxy/collection.rb', line 118 delegate_as_scope :limit |
#lock ⇒ Object
A proxy for lock
method which returns a restricted scope.
117 |
# File 'lib/heimdallr/proxy/collection.rb', line 117 delegate_as_scope :lock |
#many? ⇒ Object
A proxy for many?
method which returns a raw value.
127 |
# File 'lib/heimdallr/proxy/collection.rb', line 127 delegate_as_value :many? |
#maximum ⇒ Object
A proxy for maximum
method which returns a raw value.
137 |
# File 'lib/heimdallr/proxy/collection.rb', line 137 delegate_as_value :maximum |
#minimum ⇒ Object
A proxy for minimum
method which returns a raw value.
138 |
# File 'lib/heimdallr/proxy/collection.rb', line 138 delegate_as_value :minimum |
#new ⇒ Object
A proxy for new
method which adds fixtures to the attribute list and returns a restricted record.
109 |
# File 'lib/heimdallr/proxy/collection.rb', line 109 delegate_as_constructor :new, :assign_attributes |
#offset ⇒ Object
A proxy for offset
method which returns a restricted scope.
119 |
# File 'lib/heimdallr/proxy/collection.rb', line 119 delegate_as_scope :offset |
#order ⇒ Object
A proxy for order
method which returns a restricted scope.
120 |
# File 'lib/heimdallr/proxy/collection.rb', line 120 delegate_as_scope :order |
#pluck ⇒ Object
A proxy for pluck
method which returns a raw value.
139 |
# File 'lib/heimdallr/proxy/collection.rb', line 139 delegate_as_value :pluck |
#reflect_on_security ⇒ Hash
Return the associated security metadata. The returned hash will contain keys :context
, :scope
and :options
, corresponding to the parameters in #initialize, :model
and :restrictions
, representing the model class.
Such a name was deliberately selected for this method in order to reduce namespace pollution.
271 272 273 274 275 276 277 278 279 |
# File 'lib/heimdallr/proxy/collection.rb', line 271 def reflect_on_security { model: @scope, context: @context, scope: @scope, options: , restrictions: @restrictions, }.merge(@restrictions.reflection) end |
#reorder ⇒ Object
A proxy for reorder
method which returns a restricted scope.
121 |
# File 'lib/heimdallr/proxy/collection.rb', line 121 delegate_as_scope :reorder |
#restrict(context, options = nil) ⇒ Object
Collections cannot be restricted with different context or options.
29 30 31 32 33 34 35 |
# File 'lib/heimdallr/proxy/collection.rb', line 29 def restrict(context, =nil) if @context == context && .nil? self else raise RuntimeError, "Heimdallr proxies cannot be restricted with nonmatching context or options" end end |
#reverse_order ⇒ Object
A proxy for reverse_order
method which returns a restricted scope.
122 |
# File 'lib/heimdallr/proxy/collection.rb', line 122 delegate_as_scope :reverse_order |
#scoped ⇒ Object
A proxy for scoped
method which returns a restricted scope.
113 |
# File 'lib/heimdallr/proxy/collection.rb', line 113 delegate_as_scope :scoped |
#size ⇒ Object
A proxy for size
method which returns a raw value.
130 |
# File 'lib/heimdallr/proxy/collection.rb', line 130 delegate_as_value :size |
#sum ⇒ Object
A proxy for sum
method which returns a raw value.
136 |
# File 'lib/heimdallr/proxy/collection.rb', line 136 delegate_as_value :sum |
#to_a ⇒ Object
A proxy for to_a
method which returns an array of restricted records.
152 |
# File 'lib/heimdallr/proxy/collection.rb', line 152 delegate_as_records :to_a |
#to_ary ⇒ Object
A proxy for to_ary
method which returns an array of restricted records.
153 |
# File 'lib/heimdallr/proxy/collection.rb', line 153 delegate_as_records :to_ary |
#uniq ⇒ Object
A proxy for uniq
method which returns a restricted scope.
114 |
# File 'lib/heimdallr/proxy/collection.rb', line 114 delegate_as_scope :uniq |
#where ⇒ Object
A proxy for where
method which returns a restricted scope.
115 |
# File 'lib/heimdallr/proxy/collection.rb', line 115 delegate_as_scope :where |