Skip to content

Instantly share code, notes, and snippets.

@pmn4
Created April 4, 2020 00:53
Show Gist options
  • Save pmn4/d56b695484ece6ca6c50f4d88cb91308 to your computer and use it in GitHub Desktop.
Save pmn4/d56b695484ece6ca6c50f4d88cb91308 to your computer and use it in GitHub Desktop.
module InflateHasMany
# what #inflate is to `belongs_to` associations, #inflate_has_many is
# to `has_many` associations
# see: https://gist.github.com/pmn4/eb497edad63065304383bdfcf8d60b47
#
# returns a flatmap of all resources
def inflate_has_many(models, foreign_key, key = self.name.underscore.pluralize.to_sym, resources: nil)
models = Array(models)
# determine the set of unique, non-nil model ids
ids = models.map(&:id).uniq.compact
# fetch all resources which are referenced by any model
# then group them for fast lookup later
resources ||= where(foreign_key => ids)
resources_map = resources.group_by { |r| r.send(foreign_key) }
# models can be an array of anything, that is, items in the array do not
# have to be of the same class, just just have to respond to the key
# provided (well, the "assignment to" the key provided)
models
.select { |m| m.respond_to?(:"#{key}=") }
.each do |model|
association = model.association(key)
# using CollectionAssociation#replace here could result in a query.
# instead, we write more directly to the target array
if resources_map.key?(model.id)
resources_map[model.id]
.each { |r| association.add_to_target(r, true) }
end
# inform the association that it has been loaded, so that subsequent
# fetches do not result in a database query
association.loaded!
end
resources
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment