sunstone 5.0.0.beta3 → 5.0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.tm_properties +1 -0
- data/.travis.yml +36 -0
- data/README.md +1 -2
- data/Rakefile.rb +1 -1
- data/ext/active_record/associations/collection_association.rb +48 -6
- data/ext/active_record/attribute_methods.rb +25 -21
- data/ext/active_record/callbacks.rb +17 -0
- data/ext/active_record/finder_methods.rb +44 -2
- data/ext/active_record/persistence.rb +127 -1
- data/ext/active_record/relation.rb +13 -5
- data/ext/active_record/relation/calculations.rb +25 -0
- data/ext/active_record/statement_cache.rb +3 -2
- data/ext/active_record/transactions.rb +60 -0
- data/ext/arel/attributes/empty_relation.rb +31 -0
- data/ext/arel/attributes/relation.rb +3 -2
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +13 -2
- data/lib/active_record/connection_adapters/sunstone/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sunstone/type/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +54 -30
- data/lib/arel/collectors/sunstone.rb +6 -4
- data/lib/arel/visitors/sunstone.rb +61 -39
- data/lib/sunstone.rb +18 -11
- data/lib/sunstone/connection.rb +62 -22
- data/lib/sunstone/exception.rb +3 -0
- data/lib/sunstone/gis.rb +1 -0
- data/lib/sunstone/version.rb +2 -2
- data/sunstone.gemspec +4 -5
- data/test/active_record/associations/has_and_belongs_to_many_test.rb +12 -0
- data/test/active_record/associations/has_many_test.rb +72 -0
- data/test/active_record/eager_loading_test.rb +15 -0
- data/test/active_record/persistance_test.rb +190 -0
- data/test/active_record/preload_test.rb +16 -0
- data/test/active_record/query_test.rb +91 -0
- data/test/models.rb +91 -0
- data/test/sunstone/connection/configuration_test.rb +44 -0
- data/test/sunstone/connection/cookie_store_test.rb +37 -0
- data/test/sunstone/connection/request_helper_test.rb +105 -0
- data/test/sunstone/connection/send_request_test.rb +164 -0
- data/test/sunstone/connection_test.rb +2 -298
- data/test/test_helper.rb +45 -2
- metadata +52 -47
- data/ext/active_record/associations/builder/has_and_belongs_to_many.rb +0 -48
- data/ext/active_record/calculations.rb +0 -32
- data/ext/active_record/query_methods.rb +0 -30
- data/ext/active_record/relation/predicate_builder.rb +0 -23
- data/test/models/ship.rb +0 -14
- data/test/query_test.rb +0 -134
- data/test/sunstone/parser_test.rb +0 -124
- data/test/sunstone_test.rb +0 -303
data/lib/sunstone.rb
CHANGED
@@ -1,33 +1,40 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
require 'json'
|
1
6
|
require 'msgpack'
|
2
|
-
require '
|
3
|
-
|
4
|
-
require
|
7
|
+
require 'cookie_store' # optional
|
8
|
+
|
9
|
+
require "active_record"
|
5
10
|
|
11
|
+
# Adapter
|
6
12
|
require File.expand_path(File.join(__FILE__, '../sunstone/version'))
|
7
|
-
require File.expand_path(File.join(__FILE__, '../sunstone/connection'))
|
8
13
|
require File.expand_path(File.join(__FILE__, '../sunstone/exception'))
|
14
|
+
require File.expand_path(File.join(__FILE__, '../sunstone/connection'))
|
15
|
+
require File.expand_path(File.join(__FILE__, '../active_record/connection_adapters/sunstone_adapter'))
|
16
|
+
require File.expand_path(File.join(__FILE__, '../active_record/connection_adapters/sunstone/type_metadata'))
|
9
17
|
|
18
|
+
# Arel Adapters
|
10
19
|
require File.expand_path(File.join(__FILE__, '../arel/visitors/sunstone'))
|
11
20
|
require File.expand_path(File.join(__FILE__, '../arel/collectors/sunstone'))
|
12
21
|
|
13
|
-
|
14
|
-
require File.expand_path(File.join(__FILE__, '../active_record/connection_adapters/sunstone/type_metadata'))
|
15
|
-
|
22
|
+
# ActiveRecord Extensions
|
16
23
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/statement_cache'))
|
17
24
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/relation'))
|
25
|
+
require File.expand_path(File.join(__FILE__, '../../ext/active_record/relation/calculations'))
|
18
26
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/persistence'))
|
27
|
+
require File.expand_path(File.join(__FILE__, '../../ext/active_record/callbacks'))
|
19
28
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/attribute_methods'))
|
20
|
-
|
21
|
-
# require File.expand_path(File.join(__FILE__, '../../ext/active_record/calculations'))
|
22
|
-
require File.expand_path(File.join(__FILE__, '../../ext/active_record/query_methods'))
|
29
|
+
require File.expand_path(File.join(__FILE__, '../../ext/active_record/transactions'))
|
23
30
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/associations/collection_association'))
|
24
|
-
# require File.expand_path(File.join(__FILE__, '../../ext/active_record/associations/builder/has_and_belongs_to_many'))
|
25
31
|
|
26
32
|
require File.expand_path(File.join(__FILE__, '../../ext/active_support/core_ext/object/to_query'))
|
27
33
|
|
28
34
|
require File.expand_path(File.join(__FILE__, '../../ext/arel/select_manager'))
|
29
35
|
require File.expand_path(File.join(__FILE__, '../../ext/arel/nodes/eager_load'))
|
30
36
|
require File.expand_path(File.join(__FILE__, '../../ext/arel/attributes/relation'))
|
37
|
+
require File.expand_path(File.join(__FILE__, '../../ext/arel/attributes/empty_relation'))
|
31
38
|
require File.expand_path(File.join(__FILE__, '../../ext/arel/nodes/select_statement'))
|
32
39
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/finder_methods'))
|
33
40
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/batches'))
|
data/lib/sunstone/connection.rb
CHANGED
@@ -1,29 +1,26 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'net/http'
|
3
|
-
require 'net/https'
|
4
|
-
|
5
1
|
# _Sunstone_ is a low-level API. It provides basic HTTP #get, #post, #put, and
|
6
2
|
# #delete calls to the Sunstone Server. It can also provides basic error
|
7
3
|
# checking of responses.
|
8
4
|
module Sunstone
|
9
5
|
class Connection
|
10
6
|
|
11
|
-
# Set the User-Agent of the client. Will be joined with other User-Agent info
|
12
7
|
attr_reader :api_key, :host, :port, :use_ssl
|
13
8
|
|
14
9
|
# Initialize a connection a Sunstone API server.
|
15
10
|
#
|
16
11
|
# Options:
|
17
12
|
#
|
18
|
-
# * <tt>:
|
13
|
+
# * <tt>:url</tt> - An optional url used to set the protocol, host, port,
|
19
14
|
# and api_key
|
20
15
|
# * <tt>:host</tt> - The default is to connect to 127.0.0.1.
|
21
16
|
# * <tt>:port</tt> - Defaults to 80.
|
22
17
|
# * <tt>:use_ssl</tt> - Defaults to false.
|
23
18
|
# * <tt>:api_key</tt> - An optional token to send in the `Api-Key` header
|
19
|
+
# * <tt>:user_agent</tt> - An optional string. Will be joined with other
|
20
|
+
# User-Agent info.
|
24
21
|
def initialize(config)
|
25
|
-
if config[:
|
26
|
-
uri = URI.parse(config.delete(:
|
22
|
+
if config[:url]
|
23
|
+
uri = URI.parse(config.delete(:url))
|
27
24
|
config[:api_key] ||= (uri.user ? CGI.unescape(uri.user) : nil)
|
28
25
|
config[:host] ||= uri.host
|
29
26
|
config[:port] ||= uri.port
|
@@ -66,6 +63,10 @@ module Sunstone
|
|
66
63
|
RUBY_PLATFORM
|
67
64
|
].compact.join(' ')
|
68
65
|
end
|
66
|
+
|
67
|
+
def url(path=nil)
|
68
|
+
"http#{use_ssl ? 's' : ''}://#{host}#{port != 80 ? (port == 443 && use_ssl ? '' : ":#{port}") : ''}#{path}"
|
69
|
+
end
|
69
70
|
|
70
71
|
# Sends a Net::HTTPRequest to the server. The headers returned from
|
71
72
|
# Sunestone#headers are automatically added to the request. The appropriate
|
@@ -103,7 +104,33 @@ module Sunstone
|
|
103
104
|
# end
|
104
105
|
# end
|
105
106
|
def send_request(request, body=nil, &block)
|
106
|
-
|
107
|
+
if request.method != 'GET' && Thread.current[:sunstone_transaction_count]
|
108
|
+
if Thread.current[:sunstone_transaction_count] == 1 && !Thread.current[:sunstone_request_sent]
|
109
|
+
Thread.current[:sunstone_request_sent] = request
|
110
|
+
elsif Thread.current[:sunstone_request_sent]
|
111
|
+
log_mess = request.path.split('?', 2)
|
112
|
+
log_mess += Thread.current[:sunstone_request_sent].path.split('?', 2)
|
113
|
+
raise <<~MSG
|
114
|
+
Cannot send multiple request in a transaction.
|
115
|
+
|
116
|
+
Trying to send:
|
117
|
+
#{request.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }
|
118
|
+
|
119
|
+
Already sent:
|
120
|
+
#{Thread.current[:sunstone_request_sent].method} #{log_mess[2]} #{(log_mess[3] && !log_mess[3].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[3])) : '' }
|
121
|
+
MSG
|
122
|
+
else
|
123
|
+
log_mess = request.path.split('?', 2)
|
124
|
+
raise <<~MSG
|
125
|
+
Cannot send multiple request in a transaction.
|
126
|
+
|
127
|
+
Trying to send:
|
128
|
+
#{request.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }
|
129
|
+
MSG
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
request_uri = url(request.path)
|
107
134
|
request_headers.each { |k, v| request[k] = v }
|
108
135
|
request['Content-Type'] ||= 'application/json'
|
109
136
|
|
@@ -117,15 +144,15 @@ module Sunstone
|
|
117
144
|
elsif body.is_a?(String)
|
118
145
|
request.body = body
|
119
146
|
elsif body
|
120
|
-
request.body =
|
147
|
+
request.body = JSON.generate(body)
|
121
148
|
end
|
122
149
|
|
123
150
|
return_value = nil
|
124
151
|
retry_count = 0
|
125
152
|
begin
|
126
153
|
@connection.request(request) do |response|
|
127
|
-
if response['
|
128
|
-
|
154
|
+
if response['Deprecation-Notice']
|
155
|
+
ActiveSupport::Deprecation.warn(response['Deprecation-Notice'])
|
129
156
|
end
|
130
157
|
|
131
158
|
validate_response_code(response)
|
@@ -285,7 +312,7 @@ module Sunstone
|
|
285
312
|
end
|
286
313
|
|
287
314
|
def server_config
|
288
|
-
@server_config ||=
|
315
|
+
@server_config ||= JSON.parse(get('/config').body, symbolize_names: true)
|
289
316
|
end
|
290
317
|
|
291
318
|
private
|
@@ -329,26 +356,39 @@ module Sunstone
|
|
329
356
|
when 400
|
330
357
|
raise Sunstone::Exception::BadRequest, response.body
|
331
358
|
when 401
|
332
|
-
raise Sunstone::Exception::Unauthorized, response
|
359
|
+
raise Sunstone::Exception::Unauthorized, response.body
|
360
|
+
when 403
|
361
|
+
raise Sunstone::Exception::Forbidden, response.body
|
333
362
|
when 404
|
334
|
-
raise Sunstone::Exception::NotFound, response
|
363
|
+
raise Sunstone::Exception::NotFound, response.body
|
335
364
|
when 410
|
336
|
-
raise Sunstone::Exception::Gone, response
|
365
|
+
raise Sunstone::Exception::Gone, response.body
|
337
366
|
when 422
|
338
|
-
raise Sunstone::Exception::ApiVersionUnsupported, response
|
367
|
+
raise Sunstone::Exception::ApiVersionUnsupported, response.body
|
339
368
|
when 503
|
340
|
-
raise Sunstone::Exception::ServiceUnavailable, response
|
369
|
+
raise Sunstone::Exception::ServiceUnavailable, response.body
|
341
370
|
when 301
|
342
|
-
raise Sunstone::Exception::MovedPermanently, response
|
371
|
+
raise Sunstone::Exception::MovedPermanently, response.body
|
343
372
|
when 502
|
344
|
-
raise ActiveRecord::ConnectionNotEstablished, response
|
373
|
+
raise ActiveRecord::ConnectionNotEstablished, response.body
|
345
374
|
when 300..599
|
346
|
-
raise Sunstone::Exception, response
|
375
|
+
raise Sunstone::Exception, response.body
|
347
376
|
else
|
348
|
-
raise Sunstone::Exception, response
|
377
|
+
raise Sunstone::Exception, response.body
|
349
378
|
end
|
350
379
|
end
|
351
380
|
end
|
381
|
+
|
382
|
+
def self.use_cookie_store(store)
|
383
|
+
Thread.current[:sunstone_cookie_store] = store
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.with_cookie_store(store)
|
387
|
+
Thread.current[:sunstone_cookie_store] = store
|
388
|
+
yield
|
389
|
+
ensure
|
390
|
+
Thread.current[:sunstone_cookie_store] = nil
|
391
|
+
end
|
352
392
|
|
353
393
|
end
|
354
394
|
end
|
data/lib/sunstone/exception.rb
CHANGED
data/lib/sunstone/gis.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_record/connection_adapters/sunstone/type/ewkb'
|
data/lib/sunstone/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Sunstone
|
2
|
-
VERSION = '5.0.0.
|
3
|
-
end
|
2
|
+
VERSION = '5.0.0.1'
|
3
|
+
end
|
data/sunstone.gemspec
CHANGED
@@ -26,13 +26,12 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency 'factory_girl'
|
27
27
|
s.add_development_dependency 'webmock'
|
28
28
|
s.add_development_dependency 'sdoc-templates-42floors'
|
29
|
+
s.add_development_dependency 'rgeo'
|
30
|
+
s.add_development_dependency 'simplecov'
|
29
31
|
|
30
32
|
# Runtime
|
31
33
|
s.add_runtime_dependency 'msgpack'
|
32
|
-
s.add_runtime_dependency 'wankel'
|
33
34
|
s.add_runtime_dependency 'cookie_store'
|
34
35
|
s.add_runtime_dependency 'arel', '~> 7.0'
|
35
|
-
s.add_runtime_dependency '
|
36
|
-
|
37
|
-
s.add_runtime_dependency 'activerecord', '>= 5.0.0.beta3'
|
38
|
-
end
|
36
|
+
s.add_runtime_dependency 'activerecord', '5.0.0.1'
|
37
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::Associations::HasAndBelongsToManyTest < Minitest::Test
|
4
|
+
|
5
|
+
test '#relation_ids' do
|
6
|
+
webmock(:get, "/ships", where: {id: 42}, limit: 1).to_return(body: [{id: 42, name: "The Niña"}].to_json)
|
7
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 42}}}).to_return(body: [{id: 43, name: "Chris"}].to_json)
|
8
|
+
|
9
|
+
assert_equal [43], Ship.find(42).sailor_ids
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::Associations::HasManyTest < Minitest::Test
|
4
|
+
|
5
|
+
test '#create with has_many_ids=' do
|
6
|
+
webmock(:get, "/ships", where: {id: 2}).to_return(body: [{id: 2, fleet_id: nil, name: 'Duo'}].to_json)
|
7
|
+
webmock(:post, "/fleets").with(
|
8
|
+
body: {
|
9
|
+
fleet: {
|
10
|
+
name: 'Spanish Armada',
|
11
|
+
ships_attributes: [{id: 2, name: 'Duo'}]
|
12
|
+
}
|
13
|
+
}
|
14
|
+
).to_return(body: {id: 42, name: "Spanish Armada"}.to_json)
|
15
|
+
|
16
|
+
Fleet.create(name: 'Spanish Armada', ship_ids: [2])
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
test '#update with has_many_ids=' do
|
21
|
+
webmock(:get, "/fleets", where: {id: 42}, limit: 1).to_return(body: [{id: 42, name: "Spanish Armada"}].to_json)
|
22
|
+
webmock(:get, "/ships", where: {fleet_id: 42}).to_return(body: [].to_json)
|
23
|
+
webmock(:get, "/ships", where: {id: 2}).to_return(body: [{id: 2, fleet_id: nil, name: 'Duo'}].to_json)
|
24
|
+
|
25
|
+
webmock(:patch, "/fleets/42").with(
|
26
|
+
body: {
|
27
|
+
fleet: {
|
28
|
+
ships_attributes: [{id: 2, name: 'Duo'}]
|
29
|
+
}
|
30
|
+
}).to_return(body: {id: 42, name: "Spanish Armada"}.to_json)
|
31
|
+
|
32
|
+
Fleet.find(42).update(ship_ids: ["2"])
|
33
|
+
end
|
34
|
+
|
35
|
+
test '#save includes modified has_many associations' do
|
36
|
+
webmock(:get, '/fleets', where: {id: 1}, limit: 1, include: [:ships]).to_return({
|
37
|
+
body: [{
|
38
|
+
id: 1,
|
39
|
+
name: 'Armada Trio',
|
40
|
+
ships: [
|
41
|
+
{id: 2, fleet_id: 1, name: 'Definant'}
|
42
|
+
]
|
43
|
+
}].to_json
|
44
|
+
})
|
45
|
+
|
46
|
+
req_stub = webmock(:patch, '/fleets/1').with(
|
47
|
+
body: {
|
48
|
+
fleet: {
|
49
|
+
ships_attributes: [{ name: 'Voyager' }]
|
50
|
+
}
|
51
|
+
}.to_json
|
52
|
+
).to_return(
|
53
|
+
body: {
|
54
|
+
id: 1,
|
55
|
+
name: 'Armada Trio',
|
56
|
+
ships: [{ id: 3, fleet_id: 1, name: 'Voyager' }]
|
57
|
+
}.to_json
|
58
|
+
)
|
59
|
+
|
60
|
+
# fleet.ships = [ship]
|
61
|
+
fleet = Fleet.eager_load(:ships).find(1)
|
62
|
+
assert fleet.update(ships: [Ship.new(name: 'Voyager')])
|
63
|
+
assert_equal 1, fleet.id
|
64
|
+
assert_equal [3], fleet.ships.map(&:id)
|
65
|
+
# assert_equal 3, ship.fleet.id
|
66
|
+
# assert_equal 'Definant 001', ship.name
|
67
|
+
# assert_equal 'Armada 2', ship.fleet.name
|
68
|
+
|
69
|
+
assert_requested req_stub
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::EagerLoadingTest < Minitest::Test
|
4
|
+
|
5
|
+
test '#eager_load' do
|
6
|
+
webmock(:get, "/fleets", include: [{:ships => :sailors}]).to_return(body: [{
|
7
|
+
id: 1, ships: [{id: 1, fleet_id: 1}]
|
8
|
+
}].to_json)
|
9
|
+
|
10
|
+
fleets = Fleet.eager_load(:ships => :sailors)
|
11
|
+
assert_equal [1], fleets.map(&:id)
|
12
|
+
assert_equal [1], fleets.first.ships.map(&:id)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::PersistanceTest < Minitest::Test
|
4
|
+
|
5
|
+
class TestModelA < ExampleRecord
|
6
|
+
end
|
7
|
+
class TestModelB < ExampleRecord
|
8
|
+
before_save do
|
9
|
+
TestModelA.create
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
test '#create with errors' do
|
14
|
+
req_stub = webmock(:post, "/fleets").with(
|
15
|
+
body: { fleet: {} }.to_json
|
16
|
+
).to_return(
|
17
|
+
status: 400,
|
18
|
+
body: {name: 'Armada Uno', errors: {name: 'is required'}}.to_json
|
19
|
+
)
|
20
|
+
|
21
|
+
fleet = Fleet.create()
|
22
|
+
assert_equal ["is required"], fleet.errors[:name]
|
23
|
+
assert_requested req_stub
|
24
|
+
end
|
25
|
+
|
26
|
+
test '#create' do
|
27
|
+
req_stub = webmock(:post, "/fleets").with(
|
28
|
+
body: { fleet: {name: 'Armada Uno'} }.to_json
|
29
|
+
).to_return(
|
30
|
+
body: {id: 1, name: 'Armada Uno'}.to_json
|
31
|
+
)
|
32
|
+
|
33
|
+
Fleet.create(name: 'Armada Uno')
|
34
|
+
|
35
|
+
assert_requested req_stub
|
36
|
+
end
|
37
|
+
|
38
|
+
test '#save w/o changes' do
|
39
|
+
webmock(:get, '/fleets', where: {id: 1}, limit: 1).to_return(
|
40
|
+
body: [{id: 1, name: 'Armada Duo'}].to_json
|
41
|
+
)
|
42
|
+
|
43
|
+
fleet = Fleet.find(1)
|
44
|
+
fleet.save
|
45
|
+
|
46
|
+
assert fleet.save
|
47
|
+
assert_equal 1, fleet.id
|
48
|
+
assert_equal 'Armada Duo', fleet.name
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
test '#save attempts another request while in transaction' do
|
53
|
+
webmock(:get, '/test_model_bs/schema').to_return(
|
54
|
+
body: {
|
55
|
+
id: {type: 'integer', primary_key: true, null: false, array: false},
|
56
|
+
name: {type: 'string', primary_key: false, null: true, array: false}
|
57
|
+
}.to_json
|
58
|
+
)
|
59
|
+
webmock(:get, '/test_model_as/schema').to_return(
|
60
|
+
body: {
|
61
|
+
id: {type: 'integer', primary_key: true, null: false, array: false},
|
62
|
+
name: {type: 'string', primary_key: false, null: true, array: false}
|
63
|
+
}.to_json
|
64
|
+
)
|
65
|
+
|
66
|
+
assert_raises ActiveRecord::StatementInvalid do
|
67
|
+
TestModelB.create
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
test '#save includes modified belongs_to associations' do
|
72
|
+
ship = Ship.new(name: 'Definant', fleet: Fleet.new(name: 'Armada Duo'))
|
73
|
+
|
74
|
+
req_stub = webmock(:post, '/ships', {include: :fleet}).with(
|
75
|
+
body: {
|
76
|
+
ship: {
|
77
|
+
name: 'Definant', fleet_attributes: { name: 'Armada Duo' }
|
78
|
+
}
|
79
|
+
}.to_json
|
80
|
+
).to_return(
|
81
|
+
body: {
|
82
|
+
id: 2,
|
83
|
+
fleet_id: 3,
|
84
|
+
name: 'Definant 001',
|
85
|
+
fleet: { id: 3, name: 'Armada 2' }
|
86
|
+
}.to_json
|
87
|
+
)
|
88
|
+
|
89
|
+
assert ship.save
|
90
|
+
assert_equal 2, ship.id
|
91
|
+
assert_equal 3, ship.fleet_id
|
92
|
+
assert_equal 3, ship.fleet.id
|
93
|
+
assert_equal 'Definant 001', ship.name
|
94
|
+
assert_equal 'Armada 2', ship.fleet.name
|
95
|
+
|
96
|
+
assert_requested req_stub
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
test '#update clears belongs_to relationship' do
|
101
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
102
|
+
body: [{id: 1, fleet_id: 1, name: 'Armada Uno'}].to_json
|
103
|
+
)
|
104
|
+
req_stub = webmock(:patch, '/ships/1').with(
|
105
|
+
body: {ship: {fleet_id: nil}}.to_json
|
106
|
+
).to_return(
|
107
|
+
body: {id: 1, name: 'Armada Uno'}.to_json
|
108
|
+
)
|
109
|
+
|
110
|
+
ship = Ship.find(1)
|
111
|
+
assert ship.update(fleet: nil)
|
112
|
+
assert_requested req_stub
|
113
|
+
end
|
114
|
+
|
115
|
+
test '#update' do
|
116
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
117
|
+
body: [{id: 1, fleet_id: nil, name: 'Armada Uno'}].to_json
|
118
|
+
)
|
119
|
+
req_stub = webmock(:patch, "/ships").with(
|
120
|
+
body: { ship: { name: 'Armada Trio' } }.to_json
|
121
|
+
).to_return(
|
122
|
+
body: {id: 1, name: 'Armada Trio'}.to_json
|
123
|
+
)
|
124
|
+
|
125
|
+
Ship.find(1).update(name: 'Armada Trio')
|
126
|
+
|
127
|
+
assert_requested req_stub
|
128
|
+
end
|
129
|
+
|
130
|
+
test '#update habtm relationships' do
|
131
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
132
|
+
body: [{id: 1, fleet_id: nil, name: 'Armada Uno'}].to_json
|
133
|
+
)
|
134
|
+
webmock(:get, "/sailors", where: {id: 1}, limit: 1).to_return(
|
135
|
+
body: [{id: 1, name: 'Captain'}].to_json
|
136
|
+
)
|
137
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}).to_return(
|
138
|
+
body: [].to_json
|
139
|
+
)
|
140
|
+
req_stub = webmock(:patch, '/ships/1').with(
|
141
|
+
body: {ship: {sailors_attributes: [{id: 1, name: "Captain"}]}}.to_json
|
142
|
+
).to_return(
|
143
|
+
body: {id: 1, name: 'Armada Uno'}.to_json
|
144
|
+
)
|
145
|
+
|
146
|
+
ship = Ship.find(1)
|
147
|
+
assert ship.update(sailors: [Sailor.find(1)])
|
148
|
+
assert_requested req_stub
|
149
|
+
end
|
150
|
+
|
151
|
+
test '#update clears habtm relationship' do
|
152
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
153
|
+
body: [{id: 1, fleet_id: nil, name: 'Armada Uno'}].to_json
|
154
|
+
)
|
155
|
+
webmock(:get, "/sailors", where: {id: 1}, limit: 1).to_return(
|
156
|
+
body: [{id: 1, name: 'Captain'}].to_json
|
157
|
+
)
|
158
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}).to_return(
|
159
|
+
body: [{id: 1, name: 'Captain'}].to_json
|
160
|
+
)
|
161
|
+
req_stub = webmock(:patch, '/ships/1').with(
|
162
|
+
body: {ship: {sailors_attributes: []}}.to_json
|
163
|
+
).to_return(
|
164
|
+
body: {id: 1, name: 'Armada Uno'}.to_json
|
165
|
+
)
|
166
|
+
|
167
|
+
ship = Ship.find(1)
|
168
|
+
assert ship.update(sailors: [])
|
169
|
+
assert_requested req_stub
|
170
|
+
end
|
171
|
+
|
172
|
+
test '#update clears has_many relationship' do
|
173
|
+
webmock(:get, "/fleets", where: {id: 1}, limit: 1).to_return(
|
174
|
+
body: [{id: 1, name: 'Armada Uno'}].to_json
|
175
|
+
)
|
176
|
+
webmock(:get, "/ships", where: {fleet_id: 1}).to_return(
|
177
|
+
body: [{id: 1, name: 'Saucer Trio'}].to_json
|
178
|
+
)
|
179
|
+
req_stub = webmock(:patch, '/fleets/1').with(
|
180
|
+
body: {fleet: {ships_attributes: []}}.to_json
|
181
|
+
).to_return(
|
182
|
+
body: {id: 1, name: 'Armada Uno'}.to_json
|
183
|
+
)
|
184
|
+
|
185
|
+
fleet = Fleet.find(1)
|
186
|
+
assert fleet.update(ships: [])
|
187
|
+
assert_requested req_stub
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|