[34] pry(main)> $ User.last.to_global_id
def to_global_id(options = {})
GlobalID.create(self, options)
end
[35] pry(main)> $ GlobalID
class GlobalID
class << self
attr_reader :app
def create(model, options = {})
if app = options.fetch(:app) { GlobalID.app }
params = options.except(:app, :verifier, :for)
new URI::GID.create(app, model, params), options
else
raise ArgumentError, 'An app is required to create a GlobalID. ' \
'Pass the :app option or set the default GlobalID.app.'
end
end
...
def initialize(gid, options = {})
@uri = gid.is_a?(URI::GID) ? gid : URI::GID.parse(gid)
end
[37] pry(main)> $ URI::GID
class GID < Generic
class << self
def create(app, model, params = nil)
build app: app, model_name: model.class.name, model_id: model.id, params: params
end
def build(args)
parts = Util.make_components_hash(self, args)
parts[:host] = parts[:app]
parts[:path] = "/#{parts[:model_name]}/#{CGI.escape(parts[:model_id].to_s)}"
if parts[:params] && !parts[:params].empty?
parts[:query] = URI.encode_www_form(parts[:params])
end
super parts
end
[42] pry(main)> $ URI::GID::Generic
class Generic
def self.build(args)
if args.kind_of?(Array) &&
args.size == ::URI::Generic::COMPONENT.size
tmp = args.dup
elsif args.kind_of?(Hash)
tmp = ::URI::Generic::COMPONENT.collect do |c|
if args.include?(c)
args[c]
else
nil
end
end
else
component = self.class.component rescue ::URI::Generic::COMPONENT
raise ArgumentError,
"expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
end
tmp << nil
tmp << true
return self.new(*tmp)
end
def initialize(scheme,
userinfo, host, port, registry,
path, opaque,
query,
fragment,
parser = DEFAULT_PARSER,
arg_check = false)
@scheme = nil
@user = nil
@password = nil
@host = nil
@port = nil
@path = nil
@query = nil
@opaque = nil
@fragment = nil
@parser = parser == DEFAULT_PARSER ? nil : parser
if arg_check
self.scheme = scheme
self.userinfo = userinfo
self.hostname = host
self.port = port
self.path = path
self.query = query
self.opaque = opaque
self.fragment = fragment
else
self.set_scheme(scheme)
self.set_userinfo(userinfo)
self.set_host(host)
self.set_port(port)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
self.fragment=(fragment)
end
if registry
raise InvalidURIError,
"the scheme #{@scheme} does not accept registry part: #{registry} (or bad hostname?)"
end
@scheme&.freeze
self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
self.set_port(self.default_port) if self.default_port && !@port
end
戻ってきてGlobalID#to_s
[48] pry(main)> $ GlobalID#to_s
delegate :app, :model_name, :model_id, :params, :to_s, to: :uri
[47] pry(main)> $ URI::GID#to_s
def to_s
# Implement #to_s to avoid no implicit conversion of nil into string when path is nil
"gid://#{app}#{path}#{'?' + query if query}"
end
これがよく見る文字列になるまで
この文字列がARクラスのインスタンスに戻るまでは
[50] pry(main)> $ GlobalID::Locator.locate
def locate(gid, options = {})
if gid = GlobalID.parse(gid)
locator_for(gid).locate gid if find_allowed?(gid.model_class, options[:only])
end
end
locator_forでBaseLocatorのサブクラスのどれかが帰って、
[61] pry(main)> $ GlobalID::Locator::BaseLocator#locate
def locate(gid)
gid.model_class.find gid.model_id
end
ここでAR.findが呼ばれクエリが発行されて、無事インスタンス化