globalid 0.4.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of globalid might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 67df636d5882a415108166f9dcb39e6f92a7f5e7
4
- data.tar.gz: 5fe46ff2503cf37219c26e94e42187299523996c
2
+ SHA256:
3
+ metadata.gz: 4cfa513116ef143c878f8b6eefc242f9df668572c0ed3f3b4f5f5f87736e143f
4
+ data.tar.gz: 72e073ae2eec42a6038cda7bbf77bbeed3f72899eafe801bac1aca6c6bb24079
5
5
  SHA512:
6
- metadata.gz: f9b26b5c02b4102befdd6da829ca5e56fa0eeec953e755c2a69f77d563b3b0355c9d8ed0477e22e6230a99d851d5878c0d31b58eafc08bdcee7a8a54cd67526e
7
- data.tar.gz: c27ffc78e6679bd1c799df5c72494d77ca3106ce9c44eff7004c9e38da7749651041cf03958437f5ec41d6c3499174cc87753486193a494a4f13aaa884e233c3
6
+ metadata.gz: f3527628dfa02f3099b1c4ac0f99260f9187d83702e2cca96fab261592466fba1caa82e3dc936a54660ac9c4c0a2da087ebdabfb0d21444928979dd5cc983a34
7
+ data.tar.gz: 460c643ca0f4d0a51dc9e218da9a891f05904d75e9106692d38a46fa7cc9ad1ace229e5bce37703e2f4e62aa049246628d61de9be444a32cd2a3e6a1452d0ff3
data/README.md CHANGED
@@ -24,17 +24,17 @@ Mix `GlobalID::Identification` into any model with a `#find(id)` class method.
24
24
  Support is automatically included in Active Record.
25
25
 
26
26
  ```ruby
27
- >> person_gid = Person.find(1).to_global_id
28
- => #<GlobalID ...
27
+ person_gid = Person.find(1).to_global_id
28
+ # => #<GlobalID ...
29
29
 
30
- >> person_gid.uri
31
- => #<URI ...
30
+ person_gid.uri
31
+ # => #<URI ...
32
32
 
33
- >> person_gid.to_s
34
- => "gid://app/Person/1"
33
+ person_gid.to_s
34
+ # => "gid://app/Person/1"
35
35
 
36
- >> GlobalID::Locator.locate person_gid
37
- => #<Person:0x007fae94bf6298 @id="1">
36
+ GlobalID::Locator.locate person_gid
37
+ # => #<Person:0x007fae94bf6298 @id="1">
38
38
  ```
39
39
 
40
40
  ### Signed Global IDs
@@ -42,79 +42,125 @@ Support is automatically included in Active Record.
42
42
  For added security GlobalIDs can also be signed to ensure that the data hasn't been tampered with.
43
43
 
44
44
  ```ruby
45
- >> person_sgid = Person.find(1).to_signed_global_id
46
- => #<SignedGlobalID:0x007fea1944b410>
45
+ person_sgid = Person.find(1).to_signed_global_id
46
+ # => #<SignedGlobalID:0x007fea1944b410>
47
47
 
48
- >> person_sgid = Person.find(1).to_sgid
49
- => #<SignedGlobalID:0x007fea1944b410>
48
+ person_sgid = Person.find(1).to_sgid
49
+ # => #<SignedGlobalID:0x007fea1944b410>
50
50
 
51
- >> person_sgid.to_s
52
- => "BAhJIh5naWQ6Ly9pZGluYWlkaS9Vc2VyLzM5NTk5BjoGRVQ=--81d7358dd5ee2ca33189bb404592df5e8d11420e"
53
-
54
- >> GlobalID::Locator.locate_signed person_sgid
55
- => #<Person:0x007fae94bf6298 @id="1">
51
+ person_sgid.to_s
52
+ # => "BAhJIh5naWQ6Ly9pZGluYWlkaS9Vc2VyLzM5NTk5BjoGRVQ=--81d7358dd5ee2ca33189bb404592df5e8d11420e"
56
53
 
54
+ GlobalID::Locator.locate_signed person_sgid
55
+ # => #<Person:0x007fae94bf6298 @id="1">
57
56
  ```
58
- You can even bump the security up some more by explaining what purpose a Signed Global ID is for.
59
- In this way evildoers can't reuse a sign-up form's SGID on the login page. For example.
60
57
 
61
- ```ruby
62
- >> signup_person_sgid = Person.find(1).to_sgid(for: 'signup_form')
63
- => #<SignedGlobalID:0x007fea1984b520
64
-
65
- >> GlobalID::Locator.locate_signed(signup_person_sgid.to_s, for: 'signup_form')
66
- => #<Person:0x007fae94bf6298 @id="1">
67
- ```
58
+ **Expiration**
68
59
 
69
- You can also have SGIDs that expire some time in the future. Useful if there's a resource,
60
+ Signed Global IDs can expire some time in the future. This is useful if there's a resource
70
61
  people shouldn't have indefinite access to, like a share link.
71
62
 
72
63
  ```ruby
73
- >> expiring_sgid = Document.find(5).to_sgid(expires_in: 2.hours, for: 'sharing')
74
- => #<SignedGlobalID:0x008fde45df8937 ...>
64
+ expiring_sgid = Document.find(5).to_sgid(expires_in: 2.hours, for: 'sharing')
65
+ # => #<SignedGlobalID:0x008fde45df8937 ...>
75
66
 
76
67
  # Within 2 hours...
77
- >> GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing')
78
- => #<Document:0x007fae94bf6298 @id="5">
68
+ GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing')
69
+ # => #<Document:0x007fae94bf6298 @id="5">
79
70
 
80
71
  # More than 2 hours later...
81
- >> GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing')
82
- => nil
72
+ GlobalID::Locator.locate_signed(expiring_sgid.to_s, for: 'sharing')
73
+ # => nil
74
+ ```
83
75
 
84
- >> explicit_expiring_sgid = SecretAgentMessage.find(5).to_sgid(expires_at: Time.now.advance(hours: 1))
85
- => #<SignedGlobalID:0x008fde45df8937 ...>
76
+ **In Rails, an auto-expiry of 1 month is set by default.** You can alter that deal
77
+ in an initializer with:
86
78
 
87
- # 1 hour later...
88
- >> GlobalID::Locator.locate_signed explicit_expiring_sgid.to_s
89
- => nil
79
+ ```ruby
80
+ # config/initializers/global_id.rb
81
+ Rails.application.config.global_id.expires_in = 3.months
82
+ ```
83
+
84
+ You can assign a default SGID lifetime like so:
90
85
 
86
+ ```ruby
87
+ SignedGlobalID.expires_in = 1.month
88
+ ```
89
+
90
+ This way any generated SGID will use that relative expiry.
91
+
92
+ It's worth noting that _expiring SGIDs are not idempotent_ because they encode the current timestamp; repeated calls to `to_sgid` will produce different results. For example, in Rails
93
+
94
+ ```ruby
95
+ Document.find(5).to_sgid.to_s == Document.find(5).to_sgid.to_s
96
+ # => false
97
+ ```
98
+
99
+ You need to explicitly pass `expires_in: nil` to generate a permanent SGID that will not expire,
100
+
101
+ ```ruby
91
102
  # Passing a false value to either expiry option turns off expiration entirely.
92
- >> never_expiring_sgid = Document.find(5).to_sgid(expires_in: nil)
93
- => #<SignedGlobalID:0x008fde45df8937 ...>
103
+ never_expiring_sgid = Document.find(5).to_sgid(expires_in: nil)
104
+ # => #<SignedGlobalID:0x008fde45df8937 ...>
94
105
 
95
106
  # Any time later...
96
- >> GlobalID::Locator.locate_signed never_expiring_sgid
97
- => #<Document:0x007fae94bf6298 @id="5">
107
+ GlobalID::Locator.locate_signed never_expiring_sgid
108
+ # => #<Document:0x007fae94bf6298 @id="5">
98
109
  ```
99
110
 
111
+ It's also possible to pass a specific expiry time
112
+
113
+ ```ruby
114
+ explicit_expiring_sgid = SecretAgentMessage.find(5).to_sgid(expires_at: Time.now.advance(hours: 1))
115
+ # => #<SignedGlobalID:0x008fde45df8937 ...>
116
+
117
+ # 1 hour later...
118
+ GlobalID::Locator.locate_signed explicit_expiring_sgid.to_s
119
+ # => nil
120
+ ```
100
121
  Note that an explicit `:expires_at` takes precedence over a relative `:expires_in`.
101
122
 
102
- You can assign a default SGID lifetime like so:
123
+ **Purpose**
124
+
125
+ You can even bump the security up some more by explaining what purpose a Signed Global ID is for.
126
+ In this way evildoers can't reuse a sign-up form's SGID on the login page. For example.
103
127
 
104
128
  ```ruby
105
- SignedGlobalID.expires_in = 1.month
129
+ signup_person_sgid = Person.find(1).to_sgid(for: 'signup_form')
130
+ # => #<SignedGlobalID:0x007fea1984b520
131
+
132
+ GlobalID::Locator.locate_signed(signup_person_sgid.to_s, for: 'signup_form')
133
+ # => #<Person:0x007fae94bf6298 @id="1">
106
134
  ```
107
135
 
108
- This way any generated SGID will use that relative expiry.
136
+ ### Locating many Global IDs
109
137
 
110
- In Rails, an auto-expiry of 1 month is set by default. You can alter that deal
111
- in an initializer with:
138
+ When needing to locate many Global IDs use `GlobalID::Locator.locate_many` or `GlobalID::Locator.locate_many_signed` for Signed Global IDs to allow loading
139
+ Global IDs more efficiently.
140
+
141
+ For instance, the default locator passes every `model_id` per `model_name` thus
142
+ using `model_name.where(id: model_ids)` versus `GlobalID::Locator.locate`'s `model_name.find(id)`.
143
+
144
+ In the case of looking up Global IDs from a database, it's only necessary to query
145
+ once per `model_name` as shown here:
112
146
 
113
147
  ```ruby
114
- # config/initializers/global_id.rb
115
- Rails.application.config.global_id.expires_in = 3.months
148
+ gids = users.concat(people).sort_by(&:id).map(&:to_global_id)
149
+ # => [#<GlobalID:0x00007ffd6a8411a0 @uri=#<URI::GID gid://app/User/1>>,
150
+ #<GlobalID:0x00007ffd675d32b8 @uri=#<URI::GID gid://app/Student/1>>,
151
+ #<GlobalID:0x00007ffd6a840b10 @uri=#<URI::GID gid://app/User/2>>,
152
+ #<GlobalID:0x00007ffd675d2c28 @uri=#<URI::GID gid://app/Student/2>>,
153
+ #<GlobalID:0x00007ffd6a840480 @uri=#<URI::GID gid://app/User/3>>,
154
+ #<GlobalID:0x00007ffd675d2598 @uri=#<URI::GID gid://app/Student/3>>]
155
+
156
+ GlobalID::Locator.locate_many gids
157
+ # SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3) [["id", 1], ["id", 2], ["id", 3]]
158
+ # SELECT "students".* FROM "students" WHERE "students"."id" IN ($1, $2, $3) [["id", 1], ["id", 2], ["id", 3]]
159
+ # => [#<User id: 1>, #<Student id: 1>, #<User id: 2>, #<Student id: 2>, #<User id: 3>, #<Student id: 3>]
116
160
  ```
117
161
 
162
+ Note the order is maintained in the returned results.
163
+
118
164
  ### Custom App Locator
119
165
 
120
166
  A custom locator can be set for an app by calling `GlobalID::Locator.use` and providing an app locator to use for that app.
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GlobalID
4
+ module FixtureSet
5
+ def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
6
+ identifier = identify(label, column_type)
7
+ model_name = default_fixture_model_name(fixture_set_name)
8
+ uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
9
+
10
+ SignedGlobalID.new(uri, **options)
11
+ end
12
+ end
13
+ end
@@ -63,6 +63,11 @@ class GlobalID
63
63
  def ==(other)
64
64
  other.is_a?(GlobalID) && @uri == other.uri
65
65
  end
66
+ alias_method :eql?, :==
67
+
68
+ def hash
69
+ self.class.hash | @uri.hash
70
+ end
66
71
 
67
72
  def to_param
68
73
  # remove the = padding character for a prettier param -- it'll be added back in parse_encoded_gid
@@ -1,11 +1,7 @@
1
- require 'active_support/concern'
2
-
3
1
  class GlobalID
4
2
  module Identification
5
- extend ActiveSupport::Concern
6
-
7
3
  def to_global_id(options = {})
8
- @global_id ||= GlobalID.create(self, options)
4
+ GlobalID.create(self, options)
9
5
  end
10
6
  alias to_gid to_global_id
11
7
 
@@ -5,6 +5,7 @@ else
5
5
  require 'global_id'
6
6
  require 'active_support'
7
7
  require 'active_support/core_ext/string/inflections'
8
+ require 'active_support/core_ext/integer/time'
8
9
 
9
10
  class GlobalID
10
11
  # = GlobalID Railtie
@@ -14,14 +15,16 @@ class GlobalID
14
15
  config.eager_load_namespaces << GlobalID
15
16
 
16
17
  initializer 'global_id' do |app|
18
+ default_expires_in = 1.month
19
+ default_app_name = app.railtie_name.remove('_application').dasherize
17
20
 
18
- app.config.global_id.app ||= app.railtie_name.remove('_application').dasherize
19
- GlobalID.app = app.config.global_id.app
20
-
21
- app.config.global_id.expires_in ||= 1.month
22
- SignedGlobalID.expires_in = app.config.global_id.expires_in
21
+ GlobalID.app = app.config.global_id.app ||= default_app_name
22
+ SignedGlobalID.expires_in = app.config.global_id.fetch(:expires_in, default_expires_in)
23
23
 
24
24
  config.after_initialize do
25
+ GlobalID.app = app.config.global_id.app ||= default_app_name
26
+ SignedGlobalID.expires_in = app.config.global_id.fetch(:expires_in, default_expires_in)
27
+
25
28
  app.config.global_id.verifier ||= begin
26
29
  GlobalID::Verifier.new(app.key_generator.generate_key('signed_global_ids'))
27
30
  rescue ArgumentError
@@ -34,6 +37,11 @@ class GlobalID
34
37
  require 'global_id/identification'
35
38
  send :include, GlobalID::Identification
36
39
  end
40
+
41
+ ActiveSupport.on_load(:active_record_fixture_set) do
42
+ require 'global_id/fixture_set'
43
+ send :extend, GlobalID::FixtureSet
44
+ end
37
45
  end
38
46
  end
39
47
  end
@@ -173,5 +173,9 @@ module URI
173
173
  end
174
174
  end
175
175
 
176
- @@schemes['GID'] = GID
176
+ if respond_to?(:register_scheme)
177
+ register_scheme('GID', GID)
178
+ else
179
+ @@schemes['GID'] = GID
180
+ end
177
181
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globalid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-24 00:00:00.000000000 Z
11
+ date: 2021-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -47,6 +47,7 @@ files:
47
47
  - MIT-LICENSE
48
48
  - README.md
49
49
  - lib/global_id.rb
50
+ - lib/global_id/fixture_set.rb
50
51
  - lib/global_id/global_id.rb
51
52
  - lib/global_id/identification.rb
52
53
  - lib/global_id/locator.rb
@@ -67,15 +68,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
68
  requirements:
68
69
  - - ">="
69
70
  - !ruby/object:Gem::Version
70
- version: 1.9.3
71
+ version: 2.5.0
71
72
  required_rubygems_version: !ruby/object:Gem::Requirement
72
73
  requirements:
73
74
  - - ">="
74
75
  - !ruby/object:Gem::Version
75
76
  version: '0'
76
77
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.6.12
78
+ rubygems_version: 3.2.22
79
79
  signing_key:
80
80
  specification_version: 4
81
81
  summary: 'Refer to any model with a URI: gid://app/class/id'