diff --git a/lib/global_id/identification.rb b/lib/global_id/identification.rb index 91bc611..1cd4941 100644 --- a/lib/global_id/identification.rb +++ b/lib/global_id/identification.rb @@ -1,19 +1,118 @@ class GlobalID + # Mix `GlobalID::Identification` into any model with a `#find(id)` class + # method. Support is automatically included in Active Record. + # + # class Person + # include ActiveModel::Model + # include GlobalID::Identification + # + # attr_accessor :id + # + # def self.find(id) + # new id: id + # end + # + # def ==(other) + # id == other.try(:id) + # end + # end + # + # person_gid = Person.find(1).to_global_id + # # => # # "gid://app/Person/1" + # GlobalID::Locator.locate person_gid + # # => # module Identification + + # Returns the Global ID of the model. + # + # model = Person.new id: 1 + # global_id = model.to_global_id + # global_id.modal_class # => Person + # global_id.modal_id # => "1" + # global_id.to_param # => "Z2lkOi8vYm9yZGZvbGlvL1BlcnNvbi8x" def to_global_id(options = {}) GlobalID.create(self, options) end alias to_gid to_global_id + # Returns the Global ID parameter of the model. + # + # model = Person.new id: 1 + # model.to_gid_param # => ""Z2lkOi8vYm9yZGZvbGlvL1BlcnNvbi8x" def to_gid_param(options = {}) to_global_id(options).to_param end + # Returns the Signed Global ID of the model. + # Signed Global IDs ensure that the data hasn't been tampered with. + # + # model = Person.new id: 1 + # signed_global_id = model.to_signed_global_id + # signed_global_id.modal_class # => Person + # signed_global_id.modal_id # => "1" + # signed_global_id.to_param # => "BAh7CEkiCGdpZAY6BkVUSSIiZ2..." + # + # ==== Expiration + # + # Signed Global IDs can expire some time in the future. This is useful if + # there's a resource people shouldn't have indefinite access to, like a + # share link. + # + # expiring_sgid = Document.find(5).to_sgid(expires_in: 2.hours, for: 'sharing') + # # => # + # # Within 2 hours... + # GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing') + # # => # + # # More than 2 hours later... + # GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing') + # # => nil + # + # In Rails, an auto-expiry of 1 month is set by default. + # + # You need to explicitly pass `expires_in: nil` to generate a permanent + # SGID that will not expire, + # + # never_expiring_sgid = Document.find(5).to_sgid(expires_in: nil) + # # => # + # + # # Any time later... + # GlobalID::Locator.locate_signed never_expiring_sgid + # # => # + # + # It's also possible to pass a specific expiry time + # + # explicit_expiring_sgid = SecretAgentMessage.find(5).to_sgid(expires_at: Time.now.advance(hours: 1)) + # # => # + # + # # 1 hour later... + # GlobalID::Locator.locate_signed explicit_expiring_sgid.to_s + # # => nil + # + # Note that an explicit `:expires_at` takes precedence over a relative `:expires_in`. + # + # ==== Purpose + # + # You can even bump the security up some more by explaining what purpose a + # Signed Global ID is for. In this way evildoers can't reuse a sign-up + # form's SGID on the login page. For example. + # + # signup_person_sgid = Person.find(1).to_sgid(for: 'signup_form') + # # => # # def to_signed_global_id(options = {}) SignedGlobalID.create(self, options) end alias to_sgid to_signed_global_id + # Returns the Signed Global ID parameter. + # + # model = Person.new id: 1 + # model.to_sgid_param # => "BAh7CEkiCGdpZAY6BkVUSSIiZ2..." def to_sgid_param(options = {}) to_signed_global_id(options).to_param end