standardapi 6.1.0 → 7.1.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/README.md +80 -58
- data/lib/standard_api/access_control_list.rb +40 -6
- data/lib/standard_api/controller.rb +96 -28
- data/lib/standard_api/helpers.rb +22 -22
- data/lib/standard_api/middleware.rb +5 -0
- data/lib/standard_api/railtie.rb +17 -0
- data/lib/standard_api/route_helpers.rb +59 -9
- data/lib/standard_api/test_case/calculate_tests.rb +7 -6
- data/lib/standard_api/test_case/destroy_tests.rb +19 -7
- data/lib/standard_api/test_case/index_tests.rb +7 -13
- data/lib/standard_api/test_case/show_tests.rb +7 -7
- data/lib/standard_api/test_case/update_tests.rb +7 -6
- data/lib/standard_api/version.rb +1 -1
- data/lib/standard_api/views/application/_record.json.jbuilder +17 -6
- data/lib/standard_api/views/application/_record.streamer +4 -3
- data/lib/standard_api/views/application/_schema.json.jbuilder +20 -8
- data/lib/standard_api/views/application/_schema.streamer +22 -8
- data/lib/standard_api.rb +1 -0
- data/test/standard_api/caching_test.rb +2 -2
- data/test/standard_api/controller/include_test.rb +107 -0
- data/test/standard_api/controller/subresource_test.rb +157 -0
- data/test/standard_api/helpers_test.rb +9 -8
- data/test/standard_api/nested_attributes/belongs_to_test.rb +71 -0
- data/test/standard_api/nested_attributes/has_and_belongs_to_many_test.rb +70 -0
- data/test/standard_api/nested_attributes/has_many_test.rb +85 -0
- data/test/standard_api/nested_attributes/has_one_test.rb +71 -0
- data/test/standard_api/route_helpers_test.rb +56 -0
- data/test/standard_api/standard_api_test.rb +110 -50
- data/test/standard_api/test_app/app/controllers/acl/account_acl.rb +5 -1
- data/test/standard_api/test_app/app/controllers/acl/camera_acl.rb +7 -0
- data/test/standard_api/test_app/app/controllers/acl/photo_acl.rb +13 -0
- data/test/standard_api/test_app/app/controllers/acl/property_acl.rb +7 -1
- data/test/standard_api/test_app/controllers.rb +17 -0
- data/test/standard_api/test_app/models.rb +59 -2
- data/test/standard_api/test_app/test/factories.rb +3 -0
- data/test/standard_api/test_app/views/sessions/create.json.jbuilder +1 -0
- data/test/standard_api/test_app/views/sessions/create.streamer +3 -0
- data/test/standard_api/test_app.rb +13 -1
- data/test/standard_api/test_helper.rb +100 -7
- metadata +52 -13
@@ -22,11 +22,38 @@ module StandardAPI
|
|
22
22
|
options = resources.extract_options!.dup
|
23
23
|
|
24
24
|
resources(*resources, options) do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
block.call if block # custom routes take precedence over standardapi routes
|
26
|
+
|
27
|
+
available_actions = if only = parent_resource.instance_variable_get(:@only)
|
28
|
+
Array(only).map(&:to_sym)
|
29
|
+
else
|
30
|
+
if parent_resource.instance_variable_get(:@api_only)
|
31
|
+
[:index, :create, :show, :update, :destroy]
|
32
|
+
else
|
33
|
+
[:index, :create, :new, :show, :update, :destroy, :edit]
|
34
|
+
end + [ :schema, :calculate, :add_resource, :remove_resource, :create_resource ]
|
35
|
+
end
|
36
|
+
|
37
|
+
actions = if except = parent_resource.instance_variable_get(:@except)
|
38
|
+
available_actions - Array(except).map(&:to_sym)
|
39
|
+
else
|
40
|
+
available_actions
|
41
|
+
end
|
42
|
+
|
43
|
+
get :schema, on: :collection if actions.include?(:schema)
|
44
|
+
get :calculate, on: :collection if actions.include?(:calculate)
|
45
|
+
|
46
|
+
if actions.include?(:add_resource)
|
47
|
+
post ':relationship/:resource_id' => :add_resource, on: :member
|
48
|
+
end
|
49
|
+
|
50
|
+
if actions.include?(:create_resource)
|
51
|
+
post ':relationship' => :create_resource, on: :member
|
52
|
+
end
|
53
|
+
|
54
|
+
if actions.include?(:remove_resource)
|
55
|
+
delete ':relationship/:resource_id' => :remove_resource, on: :member
|
56
|
+
end
|
30
57
|
end
|
31
58
|
end
|
32
59
|
|
@@ -51,10 +78,33 @@ module StandardAPI
|
|
51
78
|
options = resource.extract_options!.dup
|
52
79
|
|
53
80
|
resource(*resource, options) do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
81
|
+
available_actions = if only = parent_resource.instance_variable_get(:@only)
|
82
|
+
Array(only).map(&:to_sym)
|
83
|
+
else
|
84
|
+
if parent_resource.instance_variable_get(:@api_only)
|
85
|
+
[:index, :create, :show, :update, :destroy]
|
86
|
+
else
|
87
|
+
[:index, :create, :new, :show, :update, :destroy, :edit]
|
88
|
+
end + [ :schema, :calculate, :add_resource, :remove_resource ]
|
89
|
+
end
|
90
|
+
|
91
|
+
actions = if except = parent_resource.instance_variable_get(:@except)
|
92
|
+
available_actions - Array(except).map(&:to_sym)
|
93
|
+
else
|
94
|
+
available_actions
|
95
|
+
end
|
96
|
+
|
97
|
+
get :schema, on: :collection if actions.include?(:schema)
|
98
|
+
get :calculate, on: :collection if actions.include?(:calculate)
|
99
|
+
|
100
|
+
if actions.include?(:add_resource)
|
101
|
+
post ':relationship/:resource_id' => :add_resource, on: :member
|
102
|
+
end
|
103
|
+
|
104
|
+
if actions.include?(:remove_resource)
|
105
|
+
delete ':relationship/:resource_id' => :remove_resource, on: :member
|
106
|
+
end
|
107
|
+
|
58
108
|
block.call if block
|
59
109
|
end
|
60
110
|
end
|
@@ -59,22 +59,23 @@ module StandardAPI
|
|
59
59
|
# calculations
|
60
60
|
end
|
61
61
|
|
62
|
-
test '#calculate.json
|
62
|
+
test '#calculate.json mask_for' do
|
63
63
|
# This is just to instance @controller
|
64
64
|
get resource_path(:calculate)
|
65
65
|
|
66
|
-
# If #
|
67
|
-
# test other's implementation of #
|
68
|
-
return if @controller.method(:
|
66
|
+
# If #mask isn't defined by StandardAPI we don't know how to
|
67
|
+
# test other's implementation of #mask_for. Return and don't test.
|
68
|
+
return if @controller.method(:mask_for).owner != StandardAPI
|
69
69
|
|
70
70
|
m = create_model
|
71
71
|
|
72
|
-
@controller.
|
72
|
+
@controller.define_singleton_method(:mask_for) do |table_name|
|
73
|
+
{ id: m.id + 100 }
|
74
|
+
end
|
73
75
|
selects = [{ count: :id}, { maximum: :id }, { minimum: :id }, { average: :id }]
|
74
76
|
get :calculate, select: selects, format: 'json'
|
75
77
|
assert_response :ok
|
76
78
|
assert_equal [[0, nil, nil, nil]], @controller.instance_variable_get('@calculations')
|
77
|
-
@controller.current_mask.delete(plural_name)
|
78
79
|
end
|
79
80
|
|
80
81
|
end
|
@@ -13,23 +13,35 @@ module StandardAPI
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
test '#destroy.json
|
16
|
+
test '#destroy.json mask_for' do
|
17
17
|
m = create_model
|
18
18
|
|
19
19
|
# This is just to instance @controller
|
20
20
|
get resource_path(:show, id: m.id, format: 'json')
|
21
21
|
|
22
|
-
# If #
|
23
|
-
# test other's implementation of #
|
24
|
-
return if @controller.method(:
|
22
|
+
# If #mask_for isn't defined by StandardAPI we don't know how to
|
23
|
+
# test other's implementation of #mask_for. Return and don't test.
|
24
|
+
return if @controller.method(:mask_for).owner != StandardAPI
|
25
25
|
|
26
|
-
@controller.
|
26
|
+
@controller.define_singleton_method(:mask_for) do |table_name|
|
27
|
+
{ id: m.id + 1 }
|
28
|
+
end
|
27
29
|
assert_raises(ActiveRecord::RecordNotFound) do
|
28
30
|
delete resource_path(:destroy, id: m.id, format: :json)
|
29
31
|
end
|
30
|
-
@controller.current_mask.delete(plural_name)
|
31
32
|
end
|
32
33
|
|
34
|
+
test '#destroy.json with comma separated ids' do
|
35
|
+
m1 = create_model
|
36
|
+
m2 = create_model
|
37
|
+
m3 = create_model
|
38
|
+
|
39
|
+
assert_difference("#{model.name}.count", -3) do
|
40
|
+
delete resource_path(:destroy, id: "#{m1.id},#{m2.id},#{m3.id}", format: :json)
|
41
|
+
assert_response :no_content
|
42
|
+
assert_equal '', response.body
|
43
|
+
end
|
44
|
+
end
|
33
45
|
end
|
34
46
|
end
|
35
|
-
end
|
47
|
+
end
|
@@ -117,27 +117,21 @@ module StandardAPI
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
test '#index.json
|
120
|
+
test '#index.json mask_for' do
|
121
121
|
# This is just to instance @controller
|
122
122
|
get resource_path(:index, format: :json), params: { limit: 1 }
|
123
123
|
|
124
|
-
# If #
|
125
|
-
# test other's implementation of #
|
126
|
-
return if @controller.method(:
|
124
|
+
# If #mask_for isn't defined by StandardAPI we don't know how to
|
125
|
+
# test other's implementation of #mask_for. Return and don't test.
|
126
|
+
return if @controller.method(:mask_for).owner != StandardAPI
|
127
127
|
|
128
128
|
m = create_model
|
129
|
-
@controller.
|
130
|
-
|
131
|
-
|
132
|
-
assert_equal model.where(id: m.id).sort(required_orders).to_sql, models.to_sql
|
133
|
-
@controller.current_mask.delete(plural_name)
|
134
|
-
|
135
|
-
@controller.current_mask[plural_name.to_sym] = { id: m.id }
|
129
|
+
@controller.define_singleton_method(:mask_for) do |table_name|
|
130
|
+
{ id: m.id }
|
131
|
+
end
|
136
132
|
get :index, format: :json
|
137
133
|
models = @controller.instance_variable_get("@#{plural_name}")
|
138
134
|
assert_equal model.where(id: m.id).sort(required_orders).to_sql, models.to_sql
|
139
|
-
@controller.current_mask.delete(plural_name.to_sym)
|
140
|
-
|
141
135
|
end
|
142
136
|
end
|
143
137
|
end
|
@@ -52,22 +52,22 @@ module StandardAPI
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
test '#show.json
|
55
|
+
test '#show.json mask_for' do
|
56
56
|
m = create_model
|
57
57
|
|
58
58
|
# This is just to instance @controller
|
59
59
|
get resource_path(:show, id: m.id, format: :json)
|
60
60
|
|
61
|
-
# If #
|
62
|
-
# test other's implementation of #
|
63
|
-
return if @controller.method(:
|
61
|
+
# If #mask_for isn't defined by StandardAPI we don't know how to
|
62
|
+
# test other's implementation of #mask_for. Return and don't test.
|
63
|
+
return if @controller.method(:mask_for).owner != StandardAPI
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
@controller.define_singleton_method(:mask_for) do |table_name|
|
66
|
+
{ id: m.id + 1 }
|
67
|
+
end
|
67
68
|
assert_raises(ActiveRecord::RecordNotFound) do
|
68
69
|
get resource_path(:show, id: m.id, format: :json)
|
69
70
|
end
|
70
|
-
@controller.current_mask.delete(plural_name)
|
71
71
|
end
|
72
72
|
|
73
73
|
end
|
@@ -131,21 +131,22 @@ module StandardAPI
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
test '#update.json
|
134
|
+
test '#update.json mask_for' do
|
135
135
|
m = create_model
|
136
136
|
|
137
137
|
# This is just to instance @controller
|
138
138
|
get resource_path(:index, format: :json), params: { limit: 1 }
|
139
139
|
|
140
|
-
# If #
|
141
|
-
# test other's implementation of #
|
142
|
-
return if @controller.method(:
|
140
|
+
# If #mask_for isn't defined by StandardAPI we don't know how to
|
141
|
+
# test other's implementation of #mask_for. Return and don't test.
|
142
|
+
return if @controller.method(:mask_for).owner != StandardAPI
|
143
143
|
|
144
|
-
@controller.
|
144
|
+
@controller.define_singleton_method(:mask_for) do |table_name|
|
145
|
+
{ id: m.id + 1 }
|
146
|
+
end
|
145
147
|
assert_raises(ActiveRecord::RecordNotFound) do
|
146
148
|
put resource_path(:update, :id => m.id), as: :json
|
147
149
|
end
|
148
|
-
@controller.current_mask.delete(plural_name)
|
149
150
|
end
|
150
151
|
|
151
152
|
end
|
data/lib/standard_api/version.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
record.
|
1
|
+
record.attribute_names.each do |name|
|
2
2
|
# Skip if attribute is included in excludes
|
3
|
-
next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name
|
4
|
-
|
3
|
+
next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name }
|
4
|
+
|
5
|
+
serialize_attribute(json, record, name, record.type_for_attribute(name).type)
|
5
6
|
end
|
6
7
|
|
7
8
|
includes.each do |inc, subinc|
|
@@ -30,11 +31,21 @@ includes.each do |inc, subinc|
|
|
30
31
|
end
|
31
32
|
else
|
32
33
|
can_cache = can_cache_relation?(record, inc, subinc)
|
33
|
-
|
34
|
-
|
34
|
+
cache_key = nil
|
35
|
+
|
36
|
+
if can_cache
|
37
|
+
if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
38
|
+
can_cache = can_cache && !record.send(association.foreign_key).nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
if can_cache
|
42
|
+
cache_key = association_cache_key(record, inc, subinc)
|
43
|
+
can_cache = cache_key.present?
|
44
|
+
end
|
35
45
|
end
|
46
|
+
|
36
47
|
json.set! inc do
|
37
|
-
json.cache_if!(can_cache, can_cache ?
|
48
|
+
json.cache_if!(can_cache, can_cache ? cache_key : nil) do
|
38
49
|
value = record.send(inc)
|
39
50
|
if value.nil?
|
40
51
|
json.null!
|
@@ -1,9 +1,10 @@
|
|
1
1
|
json.object! do
|
2
2
|
|
3
|
-
record.
|
3
|
+
record.attribute_names.each do |name|
|
4
4
|
# Skip if attribute is included in excludes
|
5
|
-
next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name
|
6
|
-
|
5
|
+
next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name }
|
6
|
+
|
7
|
+
serialize_attribute(json, record, name, record.type_for_attribute(name).type)
|
7
8
|
end
|
8
9
|
|
9
10
|
includes.each do |inc, subinc|
|
@@ -50,14 +50,26 @@ else
|
|
50
50
|
|
51
51
|
json.set! 'attributes' do
|
52
52
|
model.columns.each do |column|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
default = column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil
|
54
|
+
type = case model.type_for_attribute(column.name)
|
55
|
+
when ActiveRecord::Enum::EnumType
|
56
|
+
default = model.defined_enums[column.name].key(default)
|
57
|
+
"string"
|
58
|
+
else
|
59
|
+
json_column_type(column.sql_type)
|
60
|
+
end
|
61
|
+
|
62
|
+
json.set! column.name do
|
63
|
+
json.set! 'type', type
|
64
|
+
json.set! 'default', default
|
65
|
+
json.set! 'primary_key', column.name == model.primary_key
|
66
|
+
json.set! 'null', column.null
|
67
|
+
json.set! 'array', column.array
|
68
|
+
json.set! 'comment', column.comment
|
69
|
+
# TODO: it would be nice if rails responded with a true or false here
|
70
|
+
# instead of the function itself
|
71
|
+
json.set! 'auto_populated', !!column.auto_populated? if column.respond_to?(:auto_populated?)
|
72
|
+
end
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
@@ -59,14 +59,28 @@ else
|
|
59
59
|
json.set! 'attributes' do
|
60
60
|
json.object! do
|
61
61
|
model.columns.each do |column|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
default = column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil
|
63
|
+
type = case model.type_for_attribute(column.name)
|
64
|
+
when ActiveRecord::Enum::EnumType
|
65
|
+
default = model.defined_enums[column.name].key(default)
|
66
|
+
"string"
|
67
|
+
else
|
68
|
+
json_column_type(column.sql_type)
|
69
|
+
end
|
70
|
+
|
71
|
+
json.set! column.name do
|
72
|
+
json.object! do
|
73
|
+
json.set! 'type', type
|
74
|
+
json.set! 'default', default
|
75
|
+
json.set! 'primary_key', column.name == model.primary_key
|
76
|
+
json.set! 'null', column.null
|
77
|
+
json.set! 'array', column.array
|
78
|
+
json.set! 'comment', column.comment
|
79
|
+
# TODO: it would be nice if rails responded with a true or false here
|
80
|
+
# instead of the function itself
|
81
|
+
json.set! 'auto_populated', !!column.auto_populated? if column.respond_to?(:auto_populated?)
|
82
|
+
end
|
83
|
+
end
|
70
84
|
end
|
71
85
|
end
|
72
86
|
end
|
data/lib/standard_api.rb
CHANGED
@@ -32,8 +32,8 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest
|
|
32
32
|
# Two associations that reference the same model
|
33
33
|
property = create(:property)
|
34
34
|
account = create(:account, property: property, subject: property)
|
35
|
-
Account.any_instance.expects(:property_cached_at).returns(t1)
|
36
|
-
Account.any_instance.expects(:subject_cached_at).returns(t1)
|
35
|
+
Account.any_instance.expects(:property_cached_at).twice.returns(t1)
|
36
|
+
Account.any_instance.expects(:subject_cached_at).twice.returns(t1)
|
37
37
|
get account_path(account, include: { property: true, subject: true }, format: 'json')
|
38
38
|
json = JSON(response.body)
|
39
39
|
assert json.has_key?('property')
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'standard_api/test_helper'
|
2
|
+
|
3
|
+
class ControllerIncludesTest < ActionDispatch::IntegrationTest
|
4
|
+
|
5
|
+
# = Including an invalid include
|
6
|
+
|
7
|
+
test "Controller#create with a valid include" do
|
8
|
+
property = build(:property)
|
9
|
+
|
10
|
+
json = assert_difference 'Property.count', 1 do
|
11
|
+
post "/properties", params: { property: property.attributes, include: [:photos] }, as: :json
|
12
|
+
JSON.parse(response.body)
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_response :created
|
16
|
+
assert_equal [], json['photos']
|
17
|
+
end
|
18
|
+
|
19
|
+
test "Controller#update with a valid include" do
|
20
|
+
photo = create(:photo)
|
21
|
+
property = create(:property, {name: "A", photos: [photo]})
|
22
|
+
patch "/properties/#{property.id}", params: { property: {name: "B"}, include: [:photos] }, as: :json
|
23
|
+
|
24
|
+
json = JSON.parse(response.body)
|
25
|
+
assert_response :ok
|
26
|
+
assert_equal [photo.id], json['photos'].map { |j| j['id'] }
|
27
|
+
end
|
28
|
+
|
29
|
+
# test "Controller#destroy with a valid include" do
|
30
|
+
# No body is returned on a destroy so includes are used
|
31
|
+
# end
|
32
|
+
|
33
|
+
test "Controller#create_resource with a valid include" do
|
34
|
+
property = create(:property, accounts: [])
|
35
|
+
account = build(:account)
|
36
|
+
|
37
|
+
post "/properties/#{property.id}/accounts", params: { account: account.attributes, include: [:photos] }, as: :json
|
38
|
+
|
39
|
+
json = JSON.parse(response.body)
|
40
|
+
assert_response :created
|
41
|
+
assert_equal [], json['photos']
|
42
|
+
end
|
43
|
+
|
44
|
+
# test "Controller#add_resource with a valid include" do
|
45
|
+
# No body is returned on a destroy so includes are used
|
46
|
+
# end
|
47
|
+
|
48
|
+
# test "Controller#remove_resource with an invalid include" do
|
49
|
+
# No body is returned on a destroy so includes are used
|
50
|
+
# end
|
51
|
+
|
52
|
+
# = Including an invalid include
|
53
|
+
|
54
|
+
test "Controller#create with an invalid include" do
|
55
|
+
property = build(:property)
|
56
|
+
|
57
|
+
assert_no_difference 'Property.count' do
|
58
|
+
post "/properties", params: { property: property.attributes, include: [:accounts] }, as: :json
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_response :bad_request
|
62
|
+
end
|
63
|
+
|
64
|
+
test "Controller#update with an invalid include" do
|
65
|
+
property = create(:property, {name: "A"})
|
66
|
+
patch "/properties/#{property.id}", params: { property: {name: "B"}, include: [:accounts] }, as: :json
|
67
|
+
|
68
|
+
assert_response :bad_request
|
69
|
+
assert_equal 'A', property.reload.name
|
70
|
+
end
|
71
|
+
|
72
|
+
# test "Controller#destroy with an invalid include" do
|
73
|
+
# No body is returned on a destroy so includes are used
|
74
|
+
# end
|
75
|
+
|
76
|
+
test "Controller#create_resource with an invalid include" do
|
77
|
+
property = create(:property, photos: [])
|
78
|
+
photo = build(:photo)
|
79
|
+
|
80
|
+
post "/properties/#{property.id}/photos", params: { photo: photo.attributes, include: [:camera] }, as: :json
|
81
|
+
assert_equal 0, property.reload.photos.count
|
82
|
+
assert_response :bad_request
|
83
|
+
end
|
84
|
+
|
85
|
+
# This test passes because includes are not used, response is a HEAD response
|
86
|
+
# and no includes are used.
|
87
|
+
test "Controller#add_resource with an invalid include" do
|
88
|
+
property = create(:property, photos: [])
|
89
|
+
photo = create(:photo)
|
90
|
+
|
91
|
+
post "/properties/#{property.id}/photos/#{photo.id}", params: { include: [:camera] }, as: :json
|
92
|
+
assert_equal 1, property.reload.photos.count
|
93
|
+
assert_response :created
|
94
|
+
end
|
95
|
+
|
96
|
+
# This test passes because includes are not used, response is a HEAD response
|
97
|
+
# and no includes are used.
|
98
|
+
test "Controller#remove_resource with an invalid include" do
|
99
|
+
photo = create(:photo)
|
100
|
+
property = create(:property, photos: [photo])
|
101
|
+
|
102
|
+
delete "/properties/#{property.id}/photos/#{photo.id}", params: { include: [:camera] }, as: :json
|
103
|
+
assert_equal 0, property.reload.photos.count
|
104
|
+
assert_response :no_content
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'standard_api/test_helper'
|
2
|
+
|
3
|
+
class ControllerSubresourceTest < ActionDispatch::IntegrationTest
|
4
|
+
|
5
|
+
# add_resource
|
6
|
+
test 'Controller#add_resource with has_many' do
|
7
|
+
property = create(:property, photos: [])
|
8
|
+
photo = create(:photo)
|
9
|
+
|
10
|
+
post "/properties/#{property.id}/photos/#{photo.id}"
|
11
|
+
assert_equal property.photos.reload.map(&:id), [photo.id]
|
12
|
+
assert_response :created
|
13
|
+
|
14
|
+
assert_raises ActiveRecord::RecordNotFound do
|
15
|
+
post "/properties/#{property.id}/photos/9999999"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'Controller#add_resource with has_and_belongs_to_many' do
|
20
|
+
photo1 = create(:photo)
|
21
|
+
photo2 = create(:photo)
|
22
|
+
property = create(:property, photos: [photo1])
|
23
|
+
|
24
|
+
post "/properties/#{property.id}/photos/#{photo2.id}"
|
25
|
+
assert_equal property.photos.reload.map(&:id), [photo1.id, photo2.id]
|
26
|
+
assert_response :created
|
27
|
+
|
28
|
+
assert_raises ActiveRecord::RecordNotFound do
|
29
|
+
post "/properties/#{property.id}/photos/9999999"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'Controller#add_resource with belongs_to' do
|
34
|
+
photo = create(:photo)
|
35
|
+
account = create(:account)
|
36
|
+
|
37
|
+
post "/photos/#{photo.id}/account/#{account.id}"
|
38
|
+
assert_equal photo.reload.account_id, account.id
|
39
|
+
assert_response :created
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'Controller#add_resource with has_one' do
|
43
|
+
photo = create(:document)
|
44
|
+
property = create(:property)
|
45
|
+
post "/properties/#{property.id}/document/#{photo.id}"
|
46
|
+
assert_equal property.reload.document, photo
|
47
|
+
assert_response :created
|
48
|
+
end
|
49
|
+
|
50
|
+
test 'Controller#add_resource that is already there' do
|
51
|
+
photo = create(:photo)
|
52
|
+
property = create(:property, photos: [photo])
|
53
|
+
|
54
|
+
post "/properties/#{property.id}/photos/#{photo.id}"
|
55
|
+
assert_response :bad_request
|
56
|
+
assert_equal JSON(response.body), {
|
57
|
+
"errors" => [
|
58
|
+
"Relationship between Property and Photo violates unique constraints"
|
59
|
+
]
|
60
|
+
}
|
61
|
+
|
62
|
+
assert_raises ActiveRecord::RecordNotFound do
|
63
|
+
post "/properties/#{property.id}/photos/9999999"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# create_resource
|
68
|
+
test 'Controller#create_resource with has_many' do
|
69
|
+
property = create(:property, photos: [])
|
70
|
+
photo = build(:photo)
|
71
|
+
|
72
|
+
post "/properties/#{property.id}/photos", params: { photo: photo.attributes }, as: :json
|
73
|
+
assert_equal property.photos.reload.map(&:id), [JSON.parse(response.body)['id']]
|
74
|
+
assert_equal property.photos.count, 1
|
75
|
+
assert_response :created
|
76
|
+
end
|
77
|
+
|
78
|
+
test 'Controller#create_resource with has_and_belongs_to_many' do
|
79
|
+
photo1 = create(:photo)
|
80
|
+
photo2 = build(:photo)
|
81
|
+
property = create(:property, photos: [photo1])
|
82
|
+
|
83
|
+
post "/properties/#{property.id}/photos", params: { photo: photo2.attributes }, as: :json
|
84
|
+
assert_equal property.photos.reload.map(&:id).sort, [photo1.id, JSON.parse(response.body)['id']].sort
|
85
|
+
assert_equal property.photos.count, 2
|
86
|
+
assert_response :created
|
87
|
+
end
|
88
|
+
|
89
|
+
test 'Controller#create_resource with belongs_to' do
|
90
|
+
photo = create(:photo)
|
91
|
+
account = build(:account)
|
92
|
+
|
93
|
+
post "/photos/#{photo.id}/account", params: { account: account.attributes }, as: :json
|
94
|
+
assert_equal photo.reload.account_id, JSON.parse(response.body)['id']
|
95
|
+
assert_response :created
|
96
|
+
end
|
97
|
+
|
98
|
+
test 'Controller#create_resource with has_one' do
|
99
|
+
account = build(:account)
|
100
|
+
property = create(:property)
|
101
|
+
post "/properties/#{property.id}/landlord", params: { landlord: account.attributes }, as: :json
|
102
|
+
assert_equal property.reload.landlord.id, JSON.parse(response.body)['id']
|
103
|
+
assert_response :created
|
104
|
+
end
|
105
|
+
|
106
|
+
# remove_resource
|
107
|
+
test 'Controller#remove_resource' do
|
108
|
+
photo = create(:photo)
|
109
|
+
property = create(:property, photos: [photo])
|
110
|
+
assert_equal property.photos.reload, [photo]
|
111
|
+
delete "/properties/#{property.id}/photos/#{photo.id}"
|
112
|
+
assert_equal property.photos.reload, []
|
113
|
+
assert_response :no_content
|
114
|
+
|
115
|
+
assert_raises ActiveRecord::RecordNotFound do
|
116
|
+
delete "/properties/#{property.id}/photos/9999999"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
test 'Controller#remove_resource with has_one' do
|
121
|
+
photo = create(:document)
|
122
|
+
property = create(:property, document: photo)
|
123
|
+
assert_equal property.document, photo
|
124
|
+
delete "/properties/#{property.id}/document/#{photo.id}"
|
125
|
+
assert_nil property.reload.document
|
126
|
+
assert_response :no_content
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'Controller#remove_resource with belongs_to' do
|
130
|
+
account = create(:account)
|
131
|
+
photo = create(:photo, account: account)
|
132
|
+
|
133
|
+
delete "/photos/#{photo.id}/account/#{account.id}"
|
134
|
+
assert_nil photo.reload.account_id
|
135
|
+
assert_response :no_content
|
136
|
+
end
|
137
|
+
|
138
|
+
test 'Controller#remove_resource with belongs_to unless not match' do
|
139
|
+
account1 = create(:account)
|
140
|
+
account2 = create(:account)
|
141
|
+
photo = create(:photo, account: account1)
|
142
|
+
|
143
|
+
delete "/photos/#{photo.id}/account/#{account2.id}"
|
144
|
+
assert_equal photo.reload.account_id, account1.id
|
145
|
+
assert_response :not_found
|
146
|
+
end
|
147
|
+
|
148
|
+
test 'Controller#remove_resource with belongs_to unless not match and is nil' do
|
149
|
+
account = create(:account)
|
150
|
+
photo = create(:photo)
|
151
|
+
|
152
|
+
delete "/photos/#{photo.id}/account/#{account.id}"
|
153
|
+
assert_nil photo.reload.account_id
|
154
|
+
assert_response :not_found
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|