Module: Protector::Adapters::ActiveRecord::Relation
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/protector/adapters/active_record/relation.rb
Overview
Patches ActiveRecord::Relation
Instance Method Summary collapse
-
#calculate(*args) ⇒ Object
Merges current relation with restriction and calls real
calculate. - #count(*args) ⇒ Object
- #except(*args) ⇒ Object
-
#exec_queries_with_protector(*args) ⇒ Object
Patches current relation to fulfill restriction and call real
exec_queries. -
#exists?(*args) ⇒ Boolean
Merges current relation with restriction and calls real
exists?. -
#new_with_protector(*args, &block) ⇒ Object
Forwards protection subject to the new instance.
- #only(*args) ⇒ Object
-
#protector_expand_inclusion(inclusion, results = [], base = [], klass = @klass) ⇒ Object
Indexes
includesformat by actual entity class. -
#protector_meta(subject = protector_subject) ⇒ Object
Gets DSL::Meta::Box of this relation.
-
#protector_mimic_base! ⇒ Object
Makes instance of Relation duck-type compatible to AR::Base to allow proper protection block execution with itself.
-
#protector_substitute_includes(subject, relation) ⇒ Object
Swaps
includeswithpreloadif it's not referenced or merges security scope of proper class otherwise. - #sum(*args) ⇒ Object
- #unscoped ⇒ Object
Instance Method Details
#calculate(*args) ⇒ Object
Merges current relation with restriction and calls real calculate
61 62 63 64 |
# File 'lib/protector/adapters/active_record/relation.rb', line 61 def calculate(*args) return super unless protector_subject? merge(.relation).unrestrict!.calculate *args end |
#count(*args) ⇒ Object
This is here cause NullRelation can return nil from count
51 52 53 |
# File 'lib/protector/adapters/active_record/relation.rb', line 51 def count(*args) super || 0 end |
#except(*args) ⇒ Object
40 41 42 43 |
# File 'lib/protector/adapters/active_record/relation.rb', line 40 def except(*args) return super unless protector_subject? super.restrict!(protector_subject) end |
#exec_queries_with_protector(*args) ⇒ Object
Patches current relation to fulfill restriction and call real exec_queries
Patching includes:
- turning
includes(that are not referenced for eager loading) intopreload - delaying built-in preloading to the stage where selection is restricted
- merging current relation with restriction (of self and every eager association)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/protector/adapters/active_record/relation.rb', line 91 def exec_queries_with_protector(*args) return @records if loaded? return exec_queries_without_protector unless protector_subject? subject = protector_subject relation = merge(.relation).unrestrict! relation = protector_substitute_includes(subject, relation) # Preserve associations from internal loading. We are going to handle that # ourselves respecting security scopes FTW! associations, relation.preload_values = relation.preload_values, [] @records = relation.send(:exec_queries).each{|record| record.restrict!(subject)} # Now we have @records restricted properly so let's preload associations! associations.each do |association| ::ActiveRecord::Associations::Preloader.new(@records, association).run end @loaded = true @records end |
#exists?(*args) ⇒ Boolean
Merges current relation with restriction and calls real exists?
67 68 69 70 |
# File 'lib/protector/adapters/active_record/relation.rb', line 67 def exists?(*args) return super unless protector_subject? merge(.relation).unrestrict!.exists? *args end |
#new_with_protector(*args, &block) ⇒ Object
Forwards protection subject to the new instance
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/protector/adapters/active_record/relation.rb', line 73 def new_with_protector(*args, &block) return new_without_protector(*args, &block) unless protector_subject? # strong_parameters integration if Protector.config.strong_parameters? && args.first.respond_to?(:permit) Protector::ActiveRecord::StrongParameters::sanitize! args, true, end new_without_protector(*args, &block).restrict!(protector_subject) end |
#only(*args) ⇒ Object
45 46 47 48 |
# File 'lib/protector/adapters/active_record/relation.rb', line 45 def only(*args) return super unless protector_subject? super.restrict!(protector_subject) end |
#protector_expand_inclusion(inclusion, results = [], base = [], klass = @klass) ⇒ Object
Indexes includes format by actual entity class
Turns {foo: :bar} into [[Foo, :foo], [Bar, {foo: :bar}]
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/protector/adapters/active_record/relation.rb', line 166 def (inclusion, results=[], base=[], klass=@klass) if inclusion.is_a?(Hash) (inclusion, results, base, klass) else Array(inclusion).each do |i| if i.is_a?(Hash) (i, results, base, klass) else results << [ klass.reflect_on_association(i.to_sym).klass, i.to_sym ] end end end results end |
#protector_meta(subject = protector_subject) ⇒ Object
Gets DSL::Meta::Box of this relation
30 31 32 |
# File 'lib/protector/adapters/active_record/relation.rb', line 30 def (subject=protector_subject) @klass..evaluate(subject) end |
#protector_mimic_base! ⇒ Object
Makes instance of Relation duck-type compatible to AR::Base to allow proper protection block execution with itself
146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/protector/adapters/active_record/relation.rb', line 146 def protector_mimic_base! return unless Protector::Adapters::ActiveRecord.modern? class <<self # AR 4 has awfull inconsistency when it comes to method `all` # We have to mimic base class behaviour for relation we get from `unscoped` def all self end end end |
#protector_substitute_includes(subject, relation) ⇒ Object
Swaps includes with preload if it's not referenced or merges
security scope of proper class otherwise
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/protector/adapters/active_record/relation.rb', line 116 def protector_substitute_includes(subject, relation) if eager_loading? (includes_values + eager_load_values).each do |klass, path| # AR drops default_scope for eagerly loadable associations # https://github.com/inossidabile/protector/issues/3 # and so should we = klass..evaluate(subject) if .scoped? unscoped = klass.unscoped # `unscoped` gets us a relation but Protector scope is supposed # to work with AR::Base. Some versions of AR have those uncompatible # so we have to workaround it :( unscoped.protector_mimic_base! # Finally we merge unscoped basic relation extended with protection scope relation = relation.merge unscoped.instance_eval(&.scope_proc) end end else relation.preload_values += includes_values relation.includes_values = [] end relation end |
#sum(*args) ⇒ Object
This is here cause NullRelation can return nil from sum
56 57 58 |
# File 'lib/protector/adapters/active_record/relation.rb', line 56 def sum(*args) super || 0 end |
#unscoped ⇒ Object
Unscoped relation drops properties and therefore should be re-restricted
35 36 37 38 |
# File 'lib/protector/adapters/active_record/relation.rb', line 35 def unscoped return super unless protector_subject? super.restrict!(protector_subject) end |