rails / globalid

Identify app models with a URI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Idea: Locating embedded resources

stevecrozz opened this issue · comments

The code I am providing here is to illustrate an idea, a seed for discussion, not a proposal to adopt it as-is.

Nevertheless, I have put together some handy code that lets me locate resources that are embedded within other resources, for example, embedded within a serialized column, like a postgres jsonb structure. I could make another gem out of this, but some form of this idea seems pretty generally useful. I wonder if the community here has any thoughts on whether this idea is worth iterating on, or importing into the globalid project.

The concept is a regular URI::GID where a "host model" can be located in the normal way, but adds additional params to the URI::GID in order to locate an object that is only locatable within its host. This implementation imposes no requirements on the name or format of those params, only that whatever params exist can be used by the "host model" to locate the required sub-resource. The host model need only implement an instance method, gid_sublocate in this case, and given the gid property, it can do whatever work is needed to find the specified subresource.

In a nutshell, this means resources that are not normally globally addressable can become globally addressable by leaning on the addressability of some host model.

# Allows objects to be located within other objects and referenced through the
# GlobalID gem. In order to participate, the sublocatable's class must
# implement an instance method `to_global_id` and the host class must implement
# `gid_sublocate`
#
# # Returns a sublocated object if one can be found, for example:
# def gid_sublocator(gid)
#   key = gid.params[:some_key]
#   serialized_column[key]
# end
#
# # Returns a GlobalID object which will be passed to gid_sublocator to
# # locate this object later, for example:
# def to_global_id(options = {})
#   GlobalID.new(
#     URI::GID.build(
#       app: GlobalID.app,
#       model_name: 'Host::Model',
#       model_id: 123,
#       params: {
#         some_key: 'abc'
#       }
#     )
#   )
# end
class GidSublocator < GlobalID::Locator::UnscopedLocator
  def locate(gid, options = {})
    sublocate(super, gid)
  end

  def locate_many(gids, options = {})
    super.zip(gids).map do |(located, gid)|
      sublocate(located, gid)
    end
  end

  private def sublocate(located, gid)
    located.try(:gid_sublocate, gid) || located
  end
end