Module: Miscellany::ArbitraryPrefetch::ActiveRecordPatches::RelationPatch
- Defined in:
- lib/miscellany/active_record/arbitrary_prefetch.rb
Instance Method Summary collapse
- #add_prefetches!(kwargs) ⇒ Object
- #exec_queries ⇒ Object
- #normalize_prefetch_options(attr, opts) ⇒ Object
- #prefetch(**kwargs) ⇒ Object
-
#prefetch_queryset(relation, queryset) ⇒ Object
[:comments, ->{ where(favorite: true) }]- evaluate the block against the named association, the same way a Rails association scope is evaluated. -
#resolve_prefetch_scope(block) ⇒ Object
->{ comments.where(favorite: true) }- pull both the base association and the filtered queryset out of the block.
Instance Method Details
#add_prefetches!(kwargs) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 142 def add_prefetches!(kwargs) return unless kwargs.present? if ACTIVE_RECORD_VERSION < ::Gem::Version.new('7.2.0') assert_mutability! else assert_modifiable! end @values[:prefetches] ||= {} kwargs.each do |attr, opts| @values[:prefetches][attr] = (attr, opts) end self end |
#exec_queries ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 119 def exec_queries return super if loaded? records = super (@values[:prefetches] || {}).each do |_key, opts| pfc = PrefetcherContext.new(model, opts) pfc.link_models(records) unless defined?(Goldiloader) && Goldiloader.enabled? if PRE_RAILS_6_2 ::ActiveRecord::Associations::Preloader.new.preload(records, [opts[:attribute]]) else ::ActiveRecord::Associations::Preloader.new(records: records, associations: [opts[:attribute]]).call end end end records end |
#normalize_prefetch_options(attr, opts) ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 158 def (attr, opts) opts = resolve_prefetch_scope(opts) if opts.is_a?(Proc) norm = if opts.is_a?(Array) { relation: opts[0], queryset: prefetch_queryset(opts[0], opts[1]) } elsif opts.is_a?(ActiveRecord::Relation) rel_name = opts.model.name.underscore rel = (model.reflections[rel_name] || model.reflections[rel_name.pluralize])&.name { relation: rel, queryset: opts } else opts end norm[:attribute] = attr norm[:type] ||= (attr.to_s.pluralize == attr.to_s) ? :has_many : :has_one norm end |
#prefetch(**kwargs) ⇒ Object
138 139 140 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 138 def prefetch(**kwargs) spawn.add_prefetches!(kwargs) end |
#prefetch_queryset(relation, queryset) ⇒ Object
[:comments, ->{ where(favorite: true) }] - evaluate the block against the
named association, the same way a Rails association scope is evaluated.
190 191 192 193 194 195 196 197 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 190 def prefetch_queryset(relation, queryset) return queryset unless queryset.is_a?(Proc) reflection = model.reflections[relation.to_s] raise ArgumentError, "#{model} has no association named #{relation}" unless reflection reflection.klass.all.instance_exec(&queryset) end |
#resolve_prefetch_scope(block) ⇒ Object
->{ comments.where(favorite: true) } - pull both the base association and the
filtered queryset out of the block. Blocks that never name an association
(->{ Comment.where(...) }) fall back to inferring it from the Relation's model.
180 181 182 183 184 185 186 |
# File 'lib/miscellany/active_record/arbitrary_prefetch.rb', line 180 def resolve_prefetch_scope(block) raise ArgumentError, "prefetch scopes do not accept arguments" if block.arity > 0 fallback = block.binding.receiver rescue nil queryset, source_key = ScopeResolver.new(model, fallback).__evaluate__(block) source_key ? [source_key, queryset] : queryset end |