How to generate GIDs from an ActiveRecord scope

Posted . Visible to the public.

ActiveRecord provides the ids method to pluck ids from a scope, but what if you need to pluck Global IDs Show archive.org snapshot ?

While you could just call map(&:to_global_id) on your scope, this approach would instantiate each record just to do that. When you have many records, this will at the very least be slow.

Here is a method that does it for you efficiently. It respects Single Table Inheritance (STI).
Put it in your project's ApplicationRecord to make it available on all models.

class ApplicationRecord
  def self.global_ids
    # This method creates GID values for the current scope, similar to
    # ActiveRecord's `ids` method. For performance, we read id and type
    # directly from the database and create GIDs from them.
    # Note that we do not return GlobalID objects, but GID URI strings.
    columns = [primary_key]
    columns << inheritance_column if column_names.include?(inheritance_column)

    # To avoid instantiating the model class itself (which is expensive)
    # we define temporary classes which hold just enough information
    # for the GID to be built. We do this only once per type.
    anonymous_classes_by_type = Hash.new do |hash, type|
      klass = Struct.new(:id)
      klass.define_singleton_method(:name) { type }
      hash[type] = klass
    end

    # We want to use `GlobalID.create` to avoid constructing a GID
    # ourselves, and because it includes some sanity checks as well.
    pluck(*columns).map do |(id, type)|
      klass = anonymous_classes_by_type[type || name]
      GlobalID.create(klass.new(id)).to_s
    end
  end
end

Example usage:

>> User.global_ids
=> ["gid://your-app/User/1", "gid://your-app/User/2", "gid://your-app/User/3"]
>> Page.global_ids
=> ["gid://your-app/Page::BlogPost/1", "gid://your-app/Page::PressRelease/2", "gid://your-app/Page::BlogPost/3"]
Profile picture of Arne Hartherz
Arne Hartherz
Last edit
Arne Hartherz
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2020-09-18 07:32)