composite_primary_keys 11.2.0 → 11.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.rdoc +8 -0
- data/lib/composite_primary_keys.rb +1 -1
- data/lib/composite_primary_keys/base.rb +1 -1
- data/lib/composite_primary_keys/composite_arrays.rb +50 -7
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +1 -1
- data/lib/composite_primary_keys/persistence.rb +3 -2
- data/lib/composite_primary_keys/reflection.rb +15 -6
- data/lib/composite_primary_keys/relation/finder_methods.rb +5 -5
- data/lib/composite_primary_keys/version.rb +2 -2
- data/test/fixtures/cpk_with_default_value.rb +3 -0
- data/test/fixtures/cpk_with_default_values.yml +7 -0
- data/test/fixtures/db_definitions/mysql.sql +7 -1
- data/test/fixtures/db_definitions/oracle.drop.sql +3 -1
- data/test/fixtures/db_definitions/oracle.sql +8 -0
- data/test/fixtures/db_definitions/postgresql.sql +6 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/db_definitions/sqlserver.sql +8 -1
- data/test/test_composite_arrays.rb +14 -0
- data/test/test_create.rb +23 -1
- data/test/test_find.rb +8 -0
- data/test/test_ids.rb +3 -0
- metadata +7 -7
- data/test/db_test.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9568b1a0261ca52beff062804d3885a795fe4193c9289b140c49c3c36ea199fb
|
4
|
+
data.tar.gz: b458b36aa5e082fc060838953e56eaea26557c4a9570d161c03420ded1a8097e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70cbc4245e31da5701b16dfe7fa109cfe1f395311446537567804b4a378ea6cd2c33d771b00b72e6cd0833a6365b6adcba03a3df4e6564668d298d28f89abbad
|
7
|
+
data.tar.gz: 52df628c9b690b8855f8dbfb52394fca4f07d674aba598b00439cf036138ef73b7975f82c434c185b9c4d4ee4537f70070c27007c2bb5ff81422c513b1a5b96f
|
data/History.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 11.3.1 (2020-04-01)
|
2
|
+
* Fix overriding AbstractReflection for activerecord 5.2.4 (Sergey Semyonov)
|
3
|
+
* Fix handling CPK with fields containing comma (Sergey Semyonov)
|
4
|
+
* Fixed incorrect SQL condition for joining by CPK (Sergey Semyonov)
|
5
|
+
* Update travis.yml file (Sergey Semyonov)
|
6
|
+
* Add tests for composite keys with default values (Daniel Wiklund)
|
7
|
+
* Fix create record where one or more of the primary keys has a default value (Daniel Wiklund)
|
8
|
+
|
1
9
|
== 11.2.0 (2019-03-16)
|
2
10
|
* When creating new records, honor composite key autoincrementing fields if possible (Antti Pitkänen)
|
3
11
|
* Update Association#run to more closely match ActiveRecord (Fabian Mersch)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module CompositePrimaryKeys
|
2
2
|
ID_SEP = ','
|
3
3
|
ID_SET_SEP = ';'
|
4
|
+
ESCAPE_CHAR = '^'
|
4
5
|
|
5
6
|
module ArrayExtension
|
6
7
|
def to_composite_keys
|
@@ -8,12 +9,27 @@ module CompositePrimaryKeys
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
+
# Convert mixed representation of CPKs (by strings or arrays) to normalized
|
13
|
+
# representation (just by arrays).
|
14
|
+
#
|
15
|
+
# `ids` is Array that may contain:
|
16
|
+
# 1. A CPK represented by an array or a string.
|
17
|
+
# 2. An array of CPKs represented by arrays or strings.
|
18
|
+
#
|
19
|
+
# There is an issue. Let `ids` contain an array with several strings. We can't distinguish case 1
|
20
|
+
# from case 2 there in general. E.g. the item can be an array containing appropriate number of strings,
|
21
|
+
# and each string can contain appropriate number of commas. We consider case 2 to win there.
|
22
|
+
def self.normalize(ids, cpk_size)
|
12
23
|
ids.map do |id|
|
13
|
-
if id.
|
14
|
-
|
15
|
-
|
16
|
-
|
24
|
+
if Utils.cpk_as_array?(id, cpk_size) && id.any? { |item| !Utils.cpk_as_string?(item, cpk_size) }
|
25
|
+
# CPK as an array - case 1
|
26
|
+
id
|
27
|
+
elsif id.is_a?(Array)
|
28
|
+
# An array of CPKs - case 2
|
29
|
+
normalize(id, cpk_size)
|
30
|
+
elsif id.is_a?(String)
|
31
|
+
# CPK as a string - case 1
|
32
|
+
CompositeKeys.parse(id)
|
17
33
|
else
|
18
34
|
id
|
19
35
|
end
|
@@ -27,7 +43,7 @@ module CompositePrimaryKeys
|
|
27
43
|
when Array
|
28
44
|
value.to_composite_keys
|
29
45
|
when String
|
30
|
-
|
46
|
+
value.split(ID_SEP).map { |key| Utils.unescape_string_key(key) }.to_composite_keys
|
31
47
|
else
|
32
48
|
raise(ArgumentError, "Unsupported type: #{value}")
|
33
49
|
end
|
@@ -43,9 +59,36 @@ module CompositePrimaryKeys
|
|
43
59
|
|
44
60
|
def to_s
|
45
61
|
# Doing this makes it easier to parse Base#[](attr_name)
|
46
|
-
join(ID_SEP)
|
62
|
+
map { |key| Utils.escape_string_key(key.to_s) }.join(ID_SEP)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Utils
|
67
|
+
class << self
|
68
|
+
def escape_string_key(key)
|
69
|
+
key.gsub(Regexp.union(ESCAPE_CHAR, ID_SEP)) do |unsafe|
|
70
|
+
"#{ESCAPE_CHAR}#{unsafe.ord.to_s(16).upcase}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def unescape_string_key(key)
|
75
|
+
key.gsub(/#{Regexp.escape(ESCAPE_CHAR)}[0-9a-fA-F]{2}/) do |escaped|
|
76
|
+
char = escaped.slice(1, 2).hex.chr
|
77
|
+
(char == ESCAPE_CHAR || char == ID_SEP) ? char : escaped
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def cpk_as_array?(value, pk_size)
|
82
|
+
# We don't permit Array to be an element of CPK.
|
83
|
+
value.is_a?(Array) && value.size == pk_size && value.none? { |item| item.is_a?(Array) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def cpk_as_string?(value, pk_size)
|
87
|
+
value.is_a?(String) && value.count(ID_SEP) == pk_size - 1
|
88
|
+
end
|
47
89
|
end
|
48
90
|
end
|
91
|
+
private_constant :Utils
|
49
92
|
end
|
50
93
|
|
51
94
|
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
@@ -64,8 +64,9 @@ module ActiveRecord
|
|
64
64
|
new_id = self.class._insert_record(attributes_values)
|
65
65
|
|
66
66
|
# CPK
|
67
|
-
if self.composite?
|
68
|
-
|
67
|
+
if self.composite?
|
68
|
+
# Merge together the specified id with the new id (specified id gets precedence)
|
69
|
+
self.id = self.id.zip(Array(new_id)).map {|id1, id2| (id1 || id2)}
|
69
70
|
else
|
70
71
|
self.id ||= new_id if self.class.primary_key
|
71
72
|
end
|
@@ -1,19 +1,28 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Reflection
|
3
3
|
class AbstractReflection
|
4
|
-
|
4
|
+
# Overriding for activerecord v5.2.4
|
5
|
+
def join_scope(table, foreign_table, foreign_klass)
|
6
|
+
predicate_builder = predicate_builder(table)
|
7
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
8
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
9
|
+
|
5
10
|
key = join_keys.key
|
6
11
|
foreign_key = join_keys.foreign_key
|
7
12
|
|
8
13
|
# CPK
|
9
|
-
#
|
10
|
-
|
14
|
+
# klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
15
|
+
klass_scope.where!(cpk_join_predicate(table, key, foreign_table, foreign_key))
|
16
|
+
|
17
|
+
if type
|
18
|
+
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
19
|
+
end
|
11
20
|
|
12
21
|
if klass.finder_needs_type_condition?
|
13
|
-
|
14
|
-
else
|
15
|
-
constraint
|
22
|
+
klass_scope.where!(klass.send(:type_condition, table))
|
16
23
|
end
|
24
|
+
|
25
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
17
26
|
end
|
18
27
|
end
|
19
28
|
end
|
@@ -79,7 +79,7 @@ module CompositePrimaryKeys
|
|
79
79
|
|
80
80
|
# CPK
|
81
81
|
# expects_array = ids.first.kind_of?(Array)
|
82
|
-
ids = CompositePrimaryKeys.normalize(ids)
|
82
|
+
ids = CompositePrimaryKeys.normalize(ids, @klass.primary_keys.length)
|
83
83
|
expects_array = ids.flatten != ids.flatten(1)
|
84
84
|
return ids.first if expects_array && ids.first.empty?
|
85
85
|
|
@@ -156,10 +156,10 @@ module CompositePrimaryKeys
|
|
156
156
|
# CPK
|
157
157
|
if composite?
|
158
158
|
ids = if ids.length == 1
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
CompositePrimaryKeys::CompositeKeys.parse(ids.first)
|
160
|
+
else
|
161
|
+
ids.to_composite_keys
|
162
|
+
end
|
163
163
|
end
|
164
164
|
|
165
165
|
return find_some_ordered(ids) unless order_values.present?
|
@@ -215,4 +215,10 @@ create table pk_called_ids (
|
|
215
215
|
abbreviation varchar(50) default null,
|
216
216
|
description varchar(50) default null,
|
217
217
|
primary key (id, reference_code)
|
218
|
-
);
|
218
|
+
);
|
219
|
+
|
220
|
+
create table cpk_with_default_values (
|
221
|
+
record_id integer not null,
|
222
|
+
record_version varchar(50) default '' not null,
|
223
|
+
primary key (record_id, record_version)
|
224
|
+
);
|
@@ -45,4 +45,6 @@ drop table capitols;
|
|
45
45
|
drop table products_restaurants;
|
46
46
|
drop table employees_groups;
|
47
47
|
drop table pk_called_ids;
|
48
|
-
drop sequence pk_called_ids_seq;
|
48
|
+
drop sequence pk_called_ids_seq;
|
49
|
+
drop table cpk_with_default_values;
|
50
|
+
drop sequence cpk_with_default_values_seq;
|
@@ -234,3 +234,11 @@ create table pk_called_ids (
|
|
234
234
|
description varchar(50) default null,
|
235
235
|
constraint pk_called_ids_pk primary key (id, reference_code)
|
236
236
|
);
|
237
|
+
|
238
|
+
create sequence cpk_with_default_values_seq start with 1000;
|
239
|
+
|
240
|
+
create table cpk_with_default_values (
|
241
|
+
record_id int not null,
|
242
|
+
record_version varchar(50) default '' not null,
|
243
|
+
constraint cpk_with_default_values_pk primary key (record_id, record_version)
|
244
|
+
);
|
@@ -218,3 +218,9 @@ create table pk_called_ids (
|
|
218
218
|
description varchar(50) default null,
|
219
219
|
primary key (id, reference_code)
|
220
220
|
);
|
221
|
+
|
222
|
+
create table cpk_with_default_values (
|
223
|
+
record_id serial not null,
|
224
|
+
record_version varchar(50) default '' not null,
|
225
|
+
primary key (record_id, record_version)
|
226
|
+
);
|
@@ -204,3 +204,9 @@ create table pk_called_ids (
|
|
204
204
|
description varchar(50) default null,
|
205
205
|
primary key (id, reference_code)
|
206
206
|
);
|
207
|
+
|
208
|
+
create table cpk_with_default_values (
|
209
|
+
record_id integer not null,
|
210
|
+
record_version varchar(50) default '' not null,
|
211
|
+
primary key (record_id, record_version)
|
212
|
+
);
|
@@ -210,4 +210,11 @@ CREATE TABLE pk_called_ids (
|
|
210
210
|
description [varchar](50) default null
|
211
211
|
CONSTRAINT [pk_called_ids_pk] PRIMARY KEY
|
212
212
|
( [id], [reference_code] )
|
213
|
-
);
|
213
|
+
);
|
214
|
+
|
215
|
+
CREATE TABLE cpk_with_default_values (
|
216
|
+
record_id [int] IDENTITY(1000,1) NOT NULL,
|
217
|
+
record_version [varchar](50) default '' NOT NULL
|
218
|
+
CONSTRAINT [cpk_with_default_values_pk] PRIMARY KEY
|
219
|
+
( [record_id], [record_version] )
|
220
|
+
);
|
@@ -21,4 +21,18 @@ class CompositeArraysTest < ActiveSupport::TestCase
|
|
21
21
|
assert_equal CompositePrimaryKeys::CompositeKeys, keys.class
|
22
22
|
assert_equal '1,2,3', keys.to_s
|
23
23
|
end
|
24
|
+
|
25
|
+
def test_parse
|
26
|
+
assert_equal ['1', '2'], CompositePrimaryKeys::CompositeKeys.parse('1,2')
|
27
|
+
assert_equal ['The USA', '^Washington, D.C.'],
|
28
|
+
CompositePrimaryKeys::CompositeKeys.parse('The USA,^5EWashington^2C D.C.')
|
29
|
+
assert_equal ['The USA', '^Washington, D.C.'],
|
30
|
+
CompositePrimaryKeys::CompositeKeys.parse(['The USA', '^Washington, D.C.'])
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_to_s
|
34
|
+
assert_equal '1,2', CompositePrimaryKeys::CompositeKeys.new([1, 2]).to_s
|
35
|
+
assert_equal 'The USA,^5EWashington^2C D.C.',
|
36
|
+
CompositePrimaryKeys::CompositeKeys.new(['The USA', '^Washington, D.C.']).to_s
|
37
|
+
end
|
24
38
|
end
|
data/test/test_create.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../abstract_unit', __FILE__)
|
2
2
|
|
3
3
|
class TestCreate < ActiveSupport::TestCase
|
4
|
-
fixtures :articles, :students, :dorms, :rooms, :room_assignments, :reference_types, :reference_codes, :streets, :suburbs
|
4
|
+
fixtures :articles, :students, :dorms, :rooms, :room_assignments, :reference_types, :reference_codes, :streets, :suburbs, :cpk_with_default_values
|
5
5
|
|
6
6
|
CLASSES = {
|
7
7
|
:single => {
|
@@ -172,4 +172,26 @@ class TestCreate < ActiveSupport::TestCase
|
|
172
172
|
|
173
173
|
assert_equal('Validation failed: Id has already been taken', error.to_s)
|
174
174
|
end
|
175
|
+
|
176
|
+
def test_find_or_create_by
|
177
|
+
suburb = Suburb.find_by(:city_id => 3, :suburb_id => 1)
|
178
|
+
assert_nil(suburb)
|
179
|
+
|
180
|
+
suburb = Suburb.find_or_create_by!(:name => 'New Suburb', :city_id => 3, :suburb_id => 1)
|
181
|
+
refute_nil(suburb)
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_create_when_pk_has_default_value
|
185
|
+
first = CpkWithDefaultValue.create!
|
186
|
+
refute_nil(first.record_id)
|
187
|
+
assert_equal('', first.record_version)
|
188
|
+
|
189
|
+
second = CpkWithDefaultValue.create!(record_id: first.record_id, record_version: 'Same id, different version')
|
190
|
+
assert_equal(first.record_id, second.record_id)
|
191
|
+
assert_equal('Same id, different version', second.record_version)
|
192
|
+
|
193
|
+
third = CpkWithDefaultValue.create!(record_version: 'Created by version only')
|
194
|
+
refute_nil(third.record_id)
|
195
|
+
assert_equal('Created by version only', third.record_version)
|
196
|
+
end
|
175
197
|
end
|
data/test/test_find.rb
CHANGED
@@ -41,6 +41,14 @@ class TestFind < ActiveSupport::TestCase
|
|
41
41
|
assert_equal(['The Netherlands', 'Amsterdam'], capitol.id)
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_find_with_strings_with_comma_as_composite_keys
|
45
|
+
capitol = Capitol.create!(country: 'The USA', city: 'Washington, D.C.')
|
46
|
+
assert_equal ['The USA', 'Washington, D.C.'], capitol.id
|
47
|
+
|
48
|
+
assert_equal capitol, Capitol.find(['The USA', 'Washington, D.C.'])
|
49
|
+
assert_equal capitol, Capitol.find(capitol.to_param)
|
50
|
+
end
|
51
|
+
|
44
52
|
def test_find_each
|
45
53
|
room_assignments = []
|
46
54
|
RoomAssignment.find_each(:batch_size => 2) do |assignment|
|
data/test/test_ids.rb
CHANGED
@@ -40,6 +40,9 @@ class TestIds < ActiveSupport::TestCase
|
|
40
40
|
testing_with do
|
41
41
|
assert_equal '1,1', @first.to_param if composite?
|
42
42
|
end
|
43
|
+
|
44
|
+
capitol = Capitol.create!(country: 'The USA', city: 'Washington, D.C.')
|
45
|
+
assert_equal 'The USA,Washington^2C D.C.', capitol.to_param
|
43
46
|
end
|
44
47
|
|
45
48
|
def test_ids_to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 11.
|
4
|
+
version: 11.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.2.
|
19
|
+
version: 5.2.4
|
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: 5.2.
|
26
|
+
version: 5.2.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,13 +147,14 @@ files:
|
|
147
147
|
- test/connections/databases.ci.yml
|
148
148
|
- test/connections/databases.example.yml
|
149
149
|
- test/connections/databases.yml
|
150
|
-
- test/db_test.rb
|
151
150
|
- test/fixtures/article.rb
|
152
151
|
- test/fixtures/articles.yml
|
153
152
|
- test/fixtures/capitol.rb
|
154
153
|
- test/fixtures/capitols.yml
|
155
154
|
- test/fixtures/comment.rb
|
156
155
|
- test/fixtures/comments.yml
|
156
|
+
- test/fixtures/cpk_with_default_value.rb
|
157
|
+
- test/fixtures/cpk_with_default_values.yml
|
157
158
|
- test/fixtures/db_definitions/db2-create-tables.sql
|
158
159
|
- test/fixtures/db_definitions/db2-drop-tables.sql
|
159
160
|
- test/fixtures/db_definitions/mysql.sql
|
@@ -272,13 +273,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
273
|
- !ruby/object:Gem::Version
|
273
274
|
version: '0'
|
274
275
|
requirements: []
|
275
|
-
rubygems_version: 3.
|
276
|
+
rubygems_version: 3.1.2
|
276
277
|
signing_key:
|
277
278
|
specification_version: 4
|
278
279
|
summary: Composite key support for ActiveRecord
|
279
280
|
test_files:
|
280
281
|
- test/abstract_unit.rb
|
281
|
-
- test/db_test.rb
|
282
282
|
- test/README_tests.rdoc
|
283
283
|
- test/setup.rb
|
284
284
|
- test/test_aliases.rb
|
data/test/db_test.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# assoc_test.rb
|
2
|
-
|
3
|
-
path = File.expand_path(File.join(File.basename(__FILE__), "..", "lib", "composite_primary_keys"))
|
4
|
-
puts path
|
5
|
-
|
6
|
-
require File.join(path)
|
7
|
-
require 'active_record'
|
8
|
-
|
9
|
-
$configuration = {
|
10
|
-
:adapter => 'postgresql',
|
11
|
-
:database => 'cpk_test',
|
12
|
-
:username => 'postgres'
|
13
|
-
}
|
14
|
-
|
15
|
-
ActiveRecord::Base.establish_connection($configuration) unless ActiveRecord::Base.connected?
|
16
|
-
|
17
|
-
module GlobePG
|
18
|
-
class PGBase < ActiveRecord::Base
|
19
|
-
self.abstract_class = true
|
20
|
-
# establish_connection($configuration) unless connected?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module GlobePG
|
25
|
-
class TeacherToSchool < PGBase
|
26
|
-
set_table_name 'teacher_to_school'
|
27
|
-
self.primary_keys = ['teacherid', 'schoolid']
|
28
|
-
|
29
|
-
belongs_to :globe_teacher, :foreign_key => 'teacherid'
|
30
|
-
belongs_to :globe_school, :foreign_key => 'schoolid'
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module GlobePG
|
35
|
-
class GlobeSchool < PGBase
|
36
|
-
set_table_name 'globe_school'
|
37
|
-
self.primary_key = 'schoolid'
|
38
|
-
has_many :teacher_to_schools, :foreign_key => :schoolid
|
39
|
-
has_many :globe_teachers, :through => :teacher_to_schools
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
module GlobePG
|
44
|
-
class GlobeTeacher < PGBase
|
45
|
-
set_table_name 'globe_teacher'
|
46
|
-
self.primary_key = 'teacherid'
|
47
|
-
has_many :teacher_to_schools, :foreign_key => :teacherid
|
48
|
-
has_many :globe_schools, :through => :teacher_to_schools
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
teacher = GlobePG::GlobeTeacher.find_by_teacherid('ZZGLOBEY')
|
53
|
-
p teacher.globe_schools
|