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
- #creatable? ⇒ Boolean
- #create_with_protector(*args, &block) ⇒ Object
- #create_with_protector!(*args, &block) ⇒ 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
67 68 69 70 |
# File 'lib/protector/adapters/active_record/relation.rb', line 67 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
57 58 59 |
# File 'lib/protector/adapters/active_record/relation.rb', line 57 def count(*args) super || 0 end |
#creatable? ⇒ Boolean
31 32 33 |
# File 'lib/protector/adapters/active_record/relation.rb', line 31 def creatable? new.creatable? end |
#create_with_protector(*args, &block) ⇒ Object
90 91 92 93 94 95 96 97 |
# File 'lib/protector/adapters/active_record/relation.rb', line 90 def create_with_protector(*args, &block) return create_without_protector(*args, &block) unless protector_subject? create_without_protector(*args) do |instance| instance.restrict!(protector_subject) block.call(instance) if block end end |
#create_with_protector!(*args, &block) ⇒ Object
99 100 101 102 103 104 105 106 |
# File 'lib/protector/adapters/active_record/relation.rb', line 99 def create_with_protector!(*args, &block) return create_without_protector!(*args, &block) unless protector_subject? create_without_protector!(*args) do |instance| instance.restrict!(protector_subject) block.call(instance) if block end end |
#except(*args) ⇒ Object
46 47 48 49 |
# File 'lib/protector/adapters/active_record/relation.rb', line 46 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)
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/protector/adapters/active_record/relation.rb', line 115 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?
73 74 75 76 |
# File 'lib/protector/adapters/active_record/relation.rb', line 73 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
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/protector/adapters/active_record/relation.rb', line 79 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
51 52 53 54 |
# File 'lib/protector/adapters/active_record/relation.rb', line 51 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}]
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/protector/adapters/active_record/relation.rb', line 190 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
36 37 38 |
# File 'lib/protector/adapters/active_record/relation.rb', line 36 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
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/protector/adapters/active_record/relation.rb', line 170 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
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/protector/adapters/active_record/relation.rb', line 140 def protector_substitute_includes(subject, relation) if relation.eager_loading? (relation.includes_values + relation.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 .eval_scope_procs(unscoped) 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
62 63 64 |
# File 'lib/protector/adapters/active_record/relation.rb', line 62 def sum(*args) super || 0 end |
#unscoped ⇒ Object
Unscoped relation drops properties and therefore should be re-restricted
41 42 43 44 |
# File 'lib/protector/adapters/active_record/relation.rb', line 41 def unscoped return super unless protector_subject? super.restrict!(protector_subject) end |