Last active
April 4, 2020 00:51
-
-
Save pmn4/eb497edad63065304383bdfcf8d60b47 to your computer and use it in GitHub Desktop.
Inflate an array of models with a foreign key relationship in a single query (relationship: Belongs To)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module InflateBelongsTo | |
| # when you have an array of models, but want to include (or even map) | |
| # an associated resource, this method puts together a single query to | |
| # fetch the data, then appends it to the model, cutting down on total | |
| # database calls. | |
| # this does the exact same work as eager loading when you first query | |
| # for a set of models, but is especially useful if you the original | |
| # query is uneditable (not written by you) or you wish to get results | |
| # conditionally (i.e., you only want _some_ associations loaded) | |
| # | |
| # models: the array of models whose foreign key relationship you wish | |
| # to inflate | |
| # key: the instance method used to get the foreign record | |
| # key is used to construct two methods: | |
| # - `#{key}_id` for getting foreign record's id | |
| # - `#{key}=` for assignment once we've fetched | |
| # | |
| # returns an array of all resources | |
| def inflate(models, key = self.name.underscore.to_sym, resources: nil) | |
| key_id = :"#{key}_id" | |
| models = Array(models) | |
| resources ||= begin | |
| ids = models | |
| .select { |m| m.respond_to?(key_id) } | |
| .map { |m| m.send(key_id) } | |
| .uniq | |
| .compact | |
| where(id: ids) | |
| end | |
| if resources.present? | |
| resource_map = resources.map { |r| [r.id, r] }.to_h | |
| models | |
| .select { |m| m.respond_to?(:"#{key}=") } | |
| .each { |m| m.send(:"#{key}=", resource_map[m.send(key_id)]) } | |
| .each { |m| m.association(key).loaded! } | |
| end | |
| resources | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To use this code, consider a scenario where
Userinstances have a relatedProfile:Sometimes, however, you don't have the ability to edit the original query.
This uses a single query to get all profiles.
Advanced Usage #1:
Consider that a
Usercan have a parentUser:Advanced Usage #2:
Consider that you only want the profiles created within the last year: