module GlobalID::Locator - globalid-0.3.5 Documentation

# module GlobalID::Locator

### Public Class Methods

locate(gid, options = {}) click to toggle source

Takes either a GlobalID or a string that can be turned into a GlobalID

Options:

- `:only` - A class, module or Array of classes and/or modules that are allowed to be located. Passing one or more classes limits instances of returned classes to those classes or their subclasses. Passing one or more modules in limits instances of returned classes to those including that module. If no classes or modules match, `nil` is returned.

    # File lib/global_id/locator.rb, line 15
    def locate(gid, options = {})
      if gid = GlobalID.parse(gid)
        locator_for(gid).locate gid if find_allowed?(gid.model_class, options[:only])
      end
    end

locate_many(gids, options = {}) click to toggle source

Takes an array of GlobalIDs or strings that can be turned into a GlobalIDs. The GlobalIDs are located using Model.find(array_of_ids), so the models must respond to that finder signature.

This approach will efficiently call only one find (or where(id: id), when using ignore_missing) per model class, but still interpolate the results to match the order in which the gids were passed.

Options:

- `:only` - A class, module or Array of classes and/or modules that are allowed to be located. Passing one or more classes limits instances of returned classes to those classes or their subclasses. Passing one or more modules in limits instances of returned classes to those including that module. If no classes or modules match, `nil` is returned.

- `:ignore_missing` - By default, ::locate_many will call find on the model to locate the ids extracted from the GIDs. In Active Record (and other data stores following the same pattern), find will raise an exception if a named ID can't be found. When you set this option to true, we will use where(id: ids) instead, which does not raise on missing records.

    # File lib/global_id/locator.rb, line 38
    def locate_many(gids, options = {})
      if (allowed_gids = parse_allowed(gids, options[:only])).any?
        models_and_ids  = allowed_gids.collect { |gid| [ gid.model_name.constantize, gid.model_id ] }
        ids_by_model    = models_and_ids.group_by(&:first)
        loaded_by_model = Hash[ids_by_model.map { |model, ids|
          [ model, find_records(model, ids.map(&:last), ignore_missing: options[:ignore_missing]).index_by { |record| record.id.to_s } ]
        }]

        models_and_ids.collect { |(model, id)| loaded_by_model[model][id] }.compact
      else
        []
      end
    end

locate_many_signed(sgids, options = {}) click to toggle source

Takes an array of SignedGlobalIDs or strings that can be turned into a SignedGlobalIDs. The SignedGlobalIDs are located using Model.find(array_of_ids), so the models must respond to that finder signature.

This approach will efficiently call only one find per model class, but still interpolate the results to match the order in which the gids were passed.

Options:

- `:only` - A class, module or Array of classes and/or modules that are allowed to be located. Passing one or more classes limits instances of returned classes to those classes or their subclasses. Passing one or more modules in limits instances of returned classes to those including that module. If no classes or modules match, `nil` is returned.

    # File lib/global_id/locator.rb, line 77
    def locate_many_signed(sgids, options = {})
      locate_many sgids.collect { |sgid| SignedGlobalID.parse(sgid, options.slice(:for)) }.compact, options
    end

locate_signed(sgid, options = {}) click to toggle source

Takes either a SignedGlobalID or a string that can be turned into a SignedGlobalID

Options:

- `:only` - A class, module or Array of classes and/or modules that are allowed to be located. Passing one or more classes limits instances of returned classes to those classes or their subclasses. Passing one or more modules in limits instances of returned classes to those including that module. If no classes or modules match, `nil` is returned.

    # File lib/global_id/locator.rb, line 60
    def locate_signed(sgid, options = {})
      SignedGlobalID.find sgid, options
    end

use(app, locator = nil, &locator_block) click to toggle source

Tie a locator to an app. Useful when different apps collaborate and reference each others' Global IDs.

The locator can be either a block or a class.

Using a block:

    GlobalID::Locator.use :foo do |gid|
      FooRemote.const_get(gid.model_name).find(gid.model_id)
    end

Using a class:

    GlobalID::Locator.use :bar, BarLocator.new

    class BarLocator
      def locate(gid)
        @search_client.search name: gid.model_name, id: gid.model_id
      end
    end

    # File lib/global_id/locator.rb, line 101
    def use(app, locator = nil, &locator_block)
      raise ArgumentError, 'No locator provided. Pass a block or an object that responds to #locate.' unless locator || block_given?

      URI::GID.validate_app(app)

      @locators[normalize_app(app)] = locator || BlockLocator.new(locator_block)
    end

### Private Class Methods

find_allowed?(model_class, only = nil) click to toggle source

    # File lib/global_id/locator.rb, line 114
    def find_allowed?(model_class, only = nil)
      only ? Array(only).any? { |c| model_class <= c } : true
    end

find_records(model_class, ids, options) click to toggle source

    # File lib/global_id/locator.rb, line 126
    def find_records(model_class, ids, options)
      if options[:ignore_missing]
        model_class.where(id: ids)
      else
        model_class.find(ids)
      end
    end

locator_for(gid) click to toggle source

    # File lib/global_id/locator.rb, line 110
    def locator_for(gid)
      @locators.fetch(normalize_app(gid.app)) { default_locator }
    end

normalize_app(app) click to toggle source

    # File lib/global_id/locator.rb, line 122
    def normalize_app(app)
      app.to_s.downcase
    end

parse_allowed(gids, only = nil) click to toggle source

    # File lib/global_id/locator.rb, line 118
    def parse_allowed(gids, only = nil)
      gids.collect { |gid| GlobalID.parse(gid) }.compact.select { |gid| find_allowed?(gid.model_class, only) }
    end