globalid 0.3.5 → 0.3.6

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.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 14fc719e31ef97f014044c96e42be88e4b563a63
4
+ data.tar.gz: ab0206d64fb1aa095311f86e4be0636d447c28d7
5
+ SHA512:
6
+ metadata.gz: fcfdb39821eb767d1b1f8d86b60813ab4c6a85f71956e294852f279252b7cb5952c5776cceaa23d578f7163ce7431e97fbc18b272254eb15a5cfd2679efc625d
7
+ data.tar.gz: 2d7ac23c3a6eaf8036d2f42b12299b037438be020316622318f69c9a0df580dc87511610c55b316ba3fd0848e9f479912654979939077fb9f5aa28c712467b0d
@@ -11,7 +11,8 @@ class GlobalID
11
11
 
12
12
  def create(model, options = {})
13
13
  if app = options.fetch(:app) { GlobalID.app }
14
- new URI::GID.create(app, model), options
14
+ params = options.except(:app, :verifier, :for)
15
+ new URI::GID.create(app, model, params), options
15
16
  else
16
17
  raise ArgumentError, 'An app is required to create a GlobalID. ' \
17
18
  'Pass the :app option or set the default GlobalID.app.'
@@ -4,13 +4,13 @@ class GlobalID
4
4
  module Identification
5
5
  extend ActiveSupport::Concern
6
6
 
7
- def to_global_id
8
- @global_id ||= GlobalID.create(self)
7
+ def to_global_id(options = {})
8
+ @global_id ||= GlobalID.create(self, options)
9
9
  end
10
10
  alias to_gid to_global_id
11
11
 
12
- def to_gid_param
13
- to_global_id.to_param
12
+ def to_gid_param(options = {})
13
+ to_global_id(options).to_param
14
14
  end
15
15
 
16
16
  def to_signed_global_id(options = {})
@@ -19,8 +19,11 @@ class GlobalID
19
19
  end
20
20
 
21
21
  # Takes an array of GlobalIDs or strings that can be turned into a GlobalIDs.
22
- # The GlobalIDs are located using Model.find(array_of_ids), so the models must respond to
23
- # that finder signature.
22
+ # All GlobalIDs must belong to the same app, as they will be located using
23
+ # the same locator using its locate_many method.
24
+ #
25
+ # By default the GlobalIDs will be located using Model.find(array_of_ids), so the
26
+ # models must respond to that finder signature.
24
27
  #
25
28
  # This approach will efficiently call only one #find (or #where(id: id), when using ignore_missing)
26
29
  # per model class, but still interpolate the results to match the order in which the gids were passed.
@@ -37,13 +40,8 @@ class GlobalID
37
40
  # we will use #where(id: ids) instead, which does not raise on missing records.
38
41
  def locate_many(gids, options = {})
39
42
  if (allowed_gids = parse_allowed(gids, options[:only])).any?
40
- models_and_ids = allowed_gids.collect { |gid| [ gid.model_name.constantize, gid.model_id ] }
41
- ids_by_model = models_and_ids.group_by(&:first)
42
- loaded_by_model = Hash[ids_by_model.map { |model, ids|
43
- [ model, find_records(model, ids.map(&:last), ignore_missing: options[:ignore_missing]).index_by { |record| record.id.to_s } ]
44
- }]
45
-
46
- models_and_ids.collect { |(model, id)| loaded_by_model[model][id] }.compact
43
+ locator = locator_for(allowed_gids.first)
44
+ locator.locate_many(allowed_gids, options)
47
45
  else
48
46
  []
49
47
  end
@@ -108,7 +106,9 @@ class GlobalID
108
106
 
109
107
  private
110
108
  def locator_for(gid)
111
- @locators.fetch(normalize_app(gid.app)) { default_locator }
109
+ @locators.fetch(normalize_app(gid.app)) do
110
+ gid.model_class.respond_to?(:unscoped) ? UNSCOPED_LOCATOR : DEFAULT_LOCATOR
111
+ end
112
112
  end
113
113
 
114
114
  def find_allowed?(model_class, only = nil)
@@ -122,26 +122,48 @@ class GlobalID
122
122
  def normalize_app(app)
123
123
  app.to_s.downcase
124
124
  end
125
-
126
- def find_records(model_class, ids, options)
127
- if options[:ignore_missing]
128
- model_class.where(id: ids)
129
- else
130
- model_class.find(ids)
131
- end
132
- end
133
125
  end
134
126
 
135
127
  private
136
128
  @locators = {}
137
129
 
138
- class ActiveRecordFinder
130
+ class DefaultLocator
139
131
  def locate(gid)
140
132
  gid.model_class.find gid.model_id
141
133
  end
134
+
135
+ def locate_many(gids, options = {})
136
+ models_and_ids = gids.collect { |gid| [ gid.model_class, gid.model_id ] }
137
+ ids_by_model = models_and_ids.group_by(&:first)
138
+ loaded_by_model = Hash[ids_by_model.map { |model, ids|
139
+ [ model, find_records(model, ids.map(&:last), ignore_missing: options[:ignore_missing]).index_by { |record| record.id.to_s } ]
140
+ }]
141
+
142
+ models_and_ids.collect { |(model, id)| loaded_by_model[model][id] }.compact
143
+ end
144
+
145
+ private
146
+ def find_records(model_class, ids, options)
147
+ if options[:ignore_missing]
148
+ model_class.where(id: ids)
149
+ else
150
+ model_class.find(ids)
151
+ end
152
+ end
142
153
  end
154
+ DEFAULT_LOCATOR = DefaultLocator.new
143
155
 
144
- mattr_reader(:default_locator) { ActiveRecordFinder.new }
156
+ class UnscopedLocator < DefaultLocator
157
+ def locate(gid)
158
+ gid.model_class.unscoped { super }
159
+ end
160
+
161
+ private
162
+ def find_records(model_class, ids, options)
163
+ model_class.unscoped { super }
164
+ end
165
+ end
166
+ UNSCOPED_LOCATOR = UnscopedLocator.new
145
167
 
146
168
  class BlockLocator
147
169
  def initialize(block)
@@ -151,6 +173,10 @@ class GlobalID
151
173
  def locate(gid)
152
174
  @locator.call(gid)
153
175
  end
176
+
177
+ def locate_many(gids, options = {})
178
+ gids.map { |gid| locate(gid) }
179
+ end
154
180
  end
155
181
  end
156
182
  end
@@ -28,6 +28,9 @@ module URI
28
28
  alias :app :host
29
29
  attr_reader :model_name, :model_id, :params
30
30
 
31
+ # Raised when creating a Global ID for a model without an id
32
+ class MissingModelIdError < URI::InvalidComponentError; end
33
+
31
34
  class << self
32
35
  # Validates +app+'s as URI hostnames containing only alphanumeric characters
33
36
  # and hyphens. An ArgumentError is raised if +app+ is invalid.
@@ -80,8 +83,11 @@ module URI
80
83
  def build(args)
81
84
  parts = Util.make_components_hash(self, args)
82
85
  parts[:host] = parts[:app]
83
- parts[:path] = "/#{parts[:model_name]}/#{parts[:model_id]}"
84
- parts[:query] = URI.encode_www_form(parts[:params]) if parts[:params]
86
+ parts[:path] = "/#{parts[:model_name]}/#{CGI.escape(parts[:model_id].to_s)}"
87
+
88
+ if parts[:params] && !parts[:params].empty?
89
+ parts[:query] = URI.encode_www_form(parts[:params])
90
+ end
85
91
 
86
92
  super parts
87
93
  end
@@ -140,8 +146,9 @@ module URI
140
146
 
141
147
  def set_model_components(path, validate = false)
142
148
  _, model_name, model_id = path.match(PATH_REGEXP).to_a
149
+ model_id = CGI.unescape(model_id) if model_id
143
150
 
144
- validate_component(model_name) && validate_component(model_id) if validate
151
+ validate_component(model_name) && validate_model_id(model_id, model_name) if validate
145
152
 
146
153
  @model_name = model_name
147
154
  @model_id = model_id
@@ -154,6 +161,13 @@ module URI
154
161
  "Expected a URI like gid://app/Person/1234: #{inspect}"
155
162
  end
156
163
 
164
+ def validate_model_id(model_id, model_name)
165
+ return model_id unless model_id.blank?
166
+
167
+ raise MissingModelIdError, "Unable to create a Global ID for " \
168
+ "#{model_name} without a model id."
169
+ end
170
+
157
171
  def parse_query_params(query)
158
172
  Hash[URI.decode_www_form(query)].with_indifferent_access if query
159
173
  end
metadata CHANGED
@@ -1,46 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globalid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
5
- prerelease:
4
+ version: 0.3.6
6
5
  platform: ruby
7
6
  authors:
8
7
  - David Heinemeier Hansson
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-04-08 00:00:00.000000000 Z
11
+ date: 2015-08-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: 4.1.0
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: 4.1.0
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  description: URIs for your models makes it easy to pass references around.
@@ -50,37 +45,37 @@ extensions: []
50
45
  extra_rdoc_files: []
51
46
  files:
52
47
  - MIT-LICENSE
48
+ - lib/global_id.rb
53
49
  - lib/global_id/global_id.rb
54
50
  - lib/global_id/identification.rb
55
51
  - lib/global_id/locator.rb
56
52
  - lib/global_id/railtie.rb
57
53
  - lib/global_id/signed_global_id.rb
58
54
  - lib/global_id/uri/gid.rb
59
- - lib/global_id.rb
60
55
  - lib/globalid.rb
61
56
  homepage: http://www.rubyonrails.org
62
57
  licenses:
63
58
  - MIT
59
+ metadata: {}
64
60
  post_install_message:
65
61
  rdoc_options: []
66
62
  require_paths:
67
63
  - lib
68
64
  required_ruby_version: !ruby/object:Gem::Requirement
69
- none: false
70
65
  requirements:
71
- - - ! '>='
66
+ - - ">="
72
67
  - !ruby/object:Gem::Version
73
68
  version: 1.9.3
74
69
  required_rubygems_version: !ruby/object:Gem::Requirement
75
- none: false
76
70
  requirements:
77
- - - ! '>='
71
+ - - ">="
78
72
  - !ruby/object:Gem::Version
79
73
  version: '0'
80
74
  requirements: []
81
75
  rubyforge_project:
82
- rubygems_version: 1.8.23.2
76
+ rubygems_version: 2.4.7
83
77
  signing_key:
84
- specification_version: 3
85
- summary: ! 'Refer to any model with a URI: gid://app/class/id'
78
+ specification_version: 4
79
+ summary: 'Refer to any model with a URI: gid://app/class/id'
86
80
  test_files: []
81
+ has_rdoc: