{"id":13878927,"url":"https://github.com/boardfish/remote_record","last_synced_at":"2026-01-18T02:28:23.664Z","repository":{"id":46624837,"uuid":"316484311","full_name":"boardfish/remote_record","owner":"boardfish","description":"Ready-made remote resource structures.","archived":false,"fork":false,"pushed_at":"2023-03-31T15:25:47.000Z","size":362,"stargazers_count":14,"open_issues_count":18,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-13T08:33:50.560Z","etag":null,"topics":["hacktoberfest","rails","remote-record","ruby","ruby-gem","ruby-on-rails"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/remote_record","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/boardfish.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-11-27T11:34:42.000Z","updated_at":"2023-03-17T20:07:32.000Z","dependencies_parsed_at":"2023-07-13T19:49:01.791Z","dependency_job_id":null,"html_url":"https://github.com/boardfish/remote_record","commit_stats":null,"previous_names":["raisedevs/remote_record"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/boardfish/remote_record","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardfish%2Fremote_record","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardfish%2Fremote_record/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardfish%2Fremote_record/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardfish%2Fremote_record/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boardfish","download_url":"https://codeload.github.com/boardfish/remote_record/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardfish%2Fremote_record/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28526569,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","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":["hacktoberfest","rails","remote-record","ruby","ruby-gem","ruby-on-rails"],"created_at":"2024-08-06T08:02:04.441Z","updated_at":"2026-01-18T02:28:23.648Z","avatar_url":"https://github.com/boardfish.png","language":"Ruby","readme":"![Remote Record: Ready-made remote resource structures.](doc/header.svg)\n\n---\n\n![Remote Record](https://github.com/raisedevs/remote_record/workflows/Remote%20Record/badge.svg)\n[![Gem Version](https://badge.fury.io/rb/remote_record.svg)](https://badge.fury.io/rb/remote_record)\n\nEvery API speaks a different language. Maybe it's REST, maybe it's SOAP, maybe\nit's GraphQL. Maybe it's got its own Ruby client, or maybe you need to roll your\nown. But what if you could just pretend it existed in your database?\n\nRemote Record provides a consistent Active Record-inspired interface for all of\nyour application's APIs. Store remote resources by ID, and Remote Record will\nlet you access objects containing their attributes from the API. Whether you're\ndealing with a user on GitHub, a track on Spotify, a place on Google Maps, or a\nresource on your internal infrastructure, you can use Remote Record to wrap\nfetching it.\n\n## Setup\n\n### Jargon\n\n**Remote resource** - the resource on the external API that you're trying to\nreach. In this example, we're trying to fetch a GitHub user.\n\n**Reference** - your record that points at the remote resource using its ID. In\nthis example, these are `GitHub::UserReference`s.\n\n**Remote record class** - a class that defines the behavior used to fetch the\nremote resource. In this example, it's `RemoteRecord::GitHub::User`.\n\n### Creating a remote record class\n\nA standard Remote Record class looks like this. It should have a `get` method,\nwhich returns a hash of data you'd like to query on the user.\n\n`RemoteRecord::Base` exposes private methods for the `remote_resource_id` and\n`authorization` that you configure on the remote reference.\n\n```ruby\nmodule RemoteRecord\n  module GitHub\n    # :nodoc:\n    class User \u003c RemoteRecord::Base\n      def get\n        client.user(remote_resource_id)\n      end\n\n      # Implement the Collection class here for fetching multiple records.\n\n      private\n\n      def client\n        Octokit::Client.new(access_token: authorization)\n      end\n    end\n  end\nend\n```\n\nThese classes can be used in isolation and don't directly depend on Active\nRecord. You can use them outside of the context of Active Record or Rails:\n\n```ruby\nRemoteRecord::GitHub::User.new(1)\n=\u003e \u003cRemoteRecord::GitHub::User attrs={}\u003e\n```\n\nIf you call `fresh` or try to access an attribute, Remote Record will fetch the\nresource and put its data in this instance.\n\n### Creating a remote reference\n\nTo start using your remote record class, `include RemoteRecord` into your\nreference. Now, whenever you initialize an instance of your class, it'll be\nfetched.\n\nCalling `remote_record` in addition to this lets you set some options:\n\n| Key           | Default                  | Purpose                                                                                                                                                                            |\n|--------------:|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| klass         | Inferred from class name | The Remote record class to use for fetching attributes                                                                                                                             |\n| id_field      | `:remote_resource_id`    | The field on the reference that contains the remote resource ID                                                                                                                    |\n| authorization | `''`                     | An object that can be used by the remote record class to authorize a request. This can be a value, or a proc that returns a value that can be used within the remote record class. |\n| memoize       | true                     | Whether reference instances should memoize the response that populates them                                                                                                        |\n| transform     | []                       | Whether the response should be put through a transformer (under `RemoteRecord::Transformers`). See `lib/remote_record/transformers` for options.                                   |\n\n```ruby\nmodule GitHub\n  # :nodoc:\n  class UserReference \u003c ApplicationRecord\n    belongs_to :user\n    include RemoteRecord\n    remote_record do |c|\n      c.authorization { |record| record.user.github_auth_tokens.active.first.token }\n      # Defaults:\n      # c.id_field :remote_resource_id\n      # c.klass RemoteRecord::GitHub::User, # Inferred from module and class name\n      # c.memoize true\n      # c.transform []\n    end\n  end\nend\n```\n\nIf the default behavior suits you just fine, you don't even need to\nconfigure it. So at its best, Remote Record can be as lightweight as:\n\n```ruby\nclass JsonPlaceholderAPIReference \u003c ApplicationRecord\n  include RemoteRecord\n  remote_record\nend\n```\n\n## Usage\n\nNow you've got the basics lined up to start using your remote reference.\n\nWhenever you call `remote` on a `GitHub::UserReference`:\n\n```ruby\nuser.github_user_references.first.remote\n```\n\n...you'll be able to use the GitHub user's data on an instance of\n`RemoteRecord::GitHub::User`. You can call methods that return attributes on the\nuser, like `#login` or `#html_url`.\n\nFor services that manage caching by way of expiry or ETags, I recommend using\n`faraday-http-cache` for your clients and setting `memoize` to `false`. Remote\nRecord may eventually gain native support for caching your records to the\ndatabase.\n\n### `remote` scopes\n\nRemote Record also provides extensions to Active Record scopes. You can call\n`remote` on a scope to fetch all the remote resources at once. By default, this\nwill use a single request per resource, which isn't often optimal.\n\nImplement the `Collection` class under your remote record class to fetch\nmultiple records from the API in fewer requests. `all` should return an array\nof references.\n\nInheriting from `RemoteRecord::Collection` grants you some convenience methods\nyou can use to pair the remote resources from the response with your existing\nreferences. Check out the class file under `lib/remote_record` for more details.\n\n```ruby\nmodule RemoteRecord\n  module GitHub\n    # :nodoc:\n    class User \u003c RemoteRecord::Base\n      # ...\n      class Collection \u003c RemoteRecord::Collection\n        def all\n          response = client.all_users\n          match_remote_resources_by_id(response)\n        end\n\n        private\n\n        def client\n          Octokit::Client.new\n        end\n      end\n    end\n  end\nend\n```\n\nNow you're ready to fetch all your resources at once:\n\n```ruby\nGitHub::UserReference.remote.all\n```\n\n`remote.where` works in the same way, but with a parameter:\n\n```ruby\nmodule RemoteRecord\n  module GitHub\n    # :nodoc:\n    class User \u003c RemoteRecord::Base\n      # ...\n      class Collection \u003c RemoteRecord::Collection\n        def all\n          response = client.all_users\n          match_remote_resources_by_id(response)\n        end\n\n        def where(query)\n          response = client.search_users(query)\n          match_remote_resources_by_id(response)\n        end\n\n        private\n\n        def client\n          Octokit::Client.new\n        end\n      end\n    end\n  end\nend\n```\n\nNow you can call `remote.where` on remote reference classes that use\n`RemoteRecord::GitHub::User`, like this:\n\n```ruby\nGitHub::UserReference.remote.where('q=tom+repos:%3E42+followers:%3E1000')\n```\n\n*Note that the query we're expecting here comes from the Octokit gem. Your API\nclient might have a nicer interface.*\n\nIt's recommended that you include something in `where` to filter incoming\nparams. Ideally, you want to expose an interface that's as ActiveRecord-like as\npossible, e.g.:\n\n```ruby\nGitHub::UserReference.remote_where(q: 'tom', repos: '\u003e42', followers: '\u003e1000')\n```\n\nYou can use or write a `Transformer` to do this. Check out the\n`RemoteRecord::Transformers` module for examples.\n\n### `initial_attrs`\n\nBehind the scenes, `match_remote_resources` sets the remote instance's `attrs`.\nYou can do the same! If you've already fetched the data for an object, set it\nvia `attrs`, like this:\n\n```ruby\ntodo = { id: 1, title: 'Hello world' }\ntodo_reference = TodoReference.new(remote_resource_id: todo[:id])\ntodo_reference.remote.attrs = todo\n```\n\n### Forcing a fresh request\n\nYou might want to force a fresh request in some instances. To do this, call\n`fresh` on a reference, and it'll be repopulated.\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboardfish%2Fremote_record","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboardfish%2Fremote_record","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboardfish%2Fremote_record/lists"}