{"id":19806489,"url":"https://github.com/monade/auto_preload","last_synced_at":"2025-11-11T19:28:52.879Z","repository":{"id":64014965,"uuid":"530404345","full_name":"monade/auto_preload","owner":"monade","description":"A gem to parse and run preload/includes/eager_load on your model from a JSON::API formatted string.","archived":false,"fork":false,"pushed_at":"2025-01-24T11:05:00.000Z","size":25,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-02T12:55:38.498Z","etag":null,"topics":["activerecord","rails","ruby"],"latest_commit_sha":null,"homepage":"https://monade.io","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/monade.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-29T21:44:13.000Z","updated_at":"2025-01-24T11:05:04.000Z","dependencies_parsed_at":"2023-01-26T12:46:50.950Z","dependency_job_id":null,"html_url":"https://github.com/monade/auto_preload","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/monade/auto_preload","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monade%2Fauto_preload","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monade%2Fauto_preload/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monade%2Fauto_preload/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monade%2Fauto_preload/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monade","download_url":"https://codeload.github.com/monade/auto_preload/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monade%2Fauto_preload/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266663609,"owners_count":23964803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","rails","ruby"],"created_at":"2024-11-12T09:07:41.679Z","updated_at":"2025-11-11T19:28:52.814Z","avatar_url":"https://github.com/monade.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Tests](https://github.com/monade/auto_preload/actions/workflows/test.yml/badge.svg)\n[![Gem Version](https://badge.fury.io/rb/auto_preload.svg)](https://badge.fury.io/rb/auto_preload)\n\n# Auto Preload\n\nA gem to parse and run `preload`/`includes`/`eager_load` on your model from a JSON::API include string.\n\n## Installation\n\nAdd the gem to your Gemfile\n\n```ruby\ngem 'auto_preload'\n```\n\nand run the `bundle install` command.\n\n## The problem\nJSON::API allows API consumers to pass a query parameter, called `include`, to manually select which model associations should be resolved and returned in the output JSON.\n\nThis means that in your controller, you may have a dilemma:\n* If the consumer requests an association that is not preloaded, Rails will run [N+1 queries](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations), slowing down the response\n* You can't know, beforehand, which association may be requested by the consumer, since it's parametric\n* You can just preload every possible association, but you'll end up making a lot of extra (redundant) queries in most cases.\n\nThis gem tries to fix this by parsing the `include` parameter and transforming it to a `preload`, `includes` or `eager_load` call in the model.\n\n## Usage\nThis gem adds to ActiveRecord classes a couple of utility methods that will help to preload associations.\n\nTo start using it, simply pass a [JSON::API include string](https://jsonapi.org/format/#fetching-includes) to the `auto_preload` class method of a model, and it will resolve it.\n\nHere's an example:\n```ruby\n# Models declaration\nclass User \u003c ApplicationRecord\n  has_many :articles\n  has_many :comments\nend\n\nclass Comment \u003c ApplicationRecord\n  belongs_to :user\nend\n\nclass Article \u003c ApplicationRecord\n  belongs_to :user\n  has_many :comments\nend\n\n# Now calling auto_preload on User\nUser.auto_preload('*') # Equivalent to preload(:articles, :comments)\nUser.auto_preload('articles.*') # Equivalent to preload(articles: [:user, :comments])\n```\n\nThe same works also with `eager_load` and `includes`:\n```ruby\nUser.auto_eager_load('*') # Equivalent to eager_load(:articles, :comments)\nUser.auto_includes('*') # Equivalent to includes(:articles, :comments)\n```\n\n### Caveats: the `**` resolver\nYou can also use the keyword `**`, however it may take you to a loop.\n\nFor instance in this case, it would raise an error:\n```ruby\nUser.auto_preload('**') # Raises \"Too many iterations reached (101 of 100)\"\n```\nSince `User` resolves `:articles`, but `Article` declares `belongs_to :user`.\n\nTo solve this you can whitelist the associations you want to preload:\n```ruby\nclass Article \u003c ApplicationRecord\n  self.auto_preloadable = [:comments]\n  belongs_to :user\n  has_many :comments\nend\n\nclass Comment \u003c ApplicationRecord\n  self.auto_preloadable = []\n  belongs_to :user\nend\n```\n\nNow you can safely use auto_preload:\n```ruby\nUser.auto_preload('**') # Equivalent to preload(:comments, articles: :comments)\n```\n\n### Adapters\nBy default, the resolution of the expressions passed to `auto_preload` methods is resolved by the [ActiveRecord Adapter](https://github.com/monade/auto_preload/blob/master/lib/auto_preload/adapters/active_record.rb).\n\nAn Adapter is simply a class that, given a model, returns the list of the associations that can be preloaded.\n\nThe ActiveRecord Adapter uses `reflect_on_all_associations` to get this list.\n\nIn many circumstances, you don't want this. For instance, if you use `ActiveModelSerializers` gem, you want to resolve only associations that are declared in the serializer.\n\nTo do so, just change the default adapter using an initializer, in `config/initializers/auto_preload.rb`:\n```ruby\nAutoPreload.config.adapter = AutoPreload::Adapters::Serializer.new\n```\n\nOf course, you can also declare your custom Adapters, simply creating a class that implements the method `resolve_preloadables(model, options = {})` and returns a list of associations.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\nAbout Monade\n----------------\n\n![monade](https://monade.io/wp-content/uploads/2021/06/monadelogo.png)\n\nauto_preload is maintained by [mònade srl](https://monade.io/en/home-en/).\n\nWe \u003c3 open source software. [Contact us](https://monade.io/en/contact-us/) for your next project!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonade%2Fauto_preload","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonade%2Fauto_preload","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonade%2Fauto_preload/lists"}