standardapi 6.1.0 → 7.1.0

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +80 -58
  3. data/lib/standard_api/access_control_list.rb +40 -6
  4. data/lib/standard_api/controller.rb +96 -28
  5. data/lib/standard_api/helpers.rb +13 -7
  6. data/lib/standard_api/middleware.rb +5 -0
  7. data/lib/standard_api/railtie.rb +17 -0
  8. data/lib/standard_api/route_helpers.rb +59 -9
  9. data/lib/standard_api/test_case/calculate_tests.rb +7 -6
  10. data/lib/standard_api/test_case/destroy_tests.rb +19 -7
  11. data/lib/standard_api/test_case/index_tests.rb +7 -13
  12. data/lib/standard_api/test_case/show_tests.rb +7 -7
  13. data/lib/standard_api/test_case/update_tests.rb +7 -6
  14. data/lib/standard_api/version.rb +1 -1
  15. data/lib/standard_api/views/application/_record.json.jbuilder +4 -3
  16. data/lib/standard_api/views/application/_record.streamer +4 -3
  17. data/lib/standard_api/views/application/_schema.json.jbuilder +20 -8
  18. data/lib/standard_api/views/application/_schema.streamer +22 -8
  19. data/lib/standard_api.rb +1 -0
  20. data/test/standard_api/caching_test.rb +2 -2
  21. data/test/standard_api/controller/include_test.rb +107 -0
  22. data/test/standard_api/controller/subresource_test.rb +157 -0
  23. data/test/standard_api/helpers_test.rb +9 -8
  24. data/test/standard_api/nested_attributes/belongs_to_test.rb +71 -0
  25. data/test/standard_api/nested_attributes/has_and_belongs_to_many_test.rb +70 -0
  26. data/test/standard_api/nested_attributes/has_many_test.rb +85 -0
  27. data/test/standard_api/nested_attributes/has_one_test.rb +71 -0
  28. data/test/standard_api/route_helpers_test.rb +56 -0
  29. data/test/standard_api/standard_api_test.rb +80 -50
  30. data/test/standard_api/test_app/app/controllers/acl/camera_acl.rb +7 -0
  31. data/test/standard_api/test_app/app/controllers/acl/photo_acl.rb +13 -0
  32. data/test/standard_api/test_app/app/controllers/acl/property_acl.rb +7 -1
  33. data/test/standard_api/test_app/controllers.rb +17 -0
  34. data/test/standard_api/test_app/models.rb +59 -2
  35. data/test/standard_api/test_app/test/factories.rb +3 -0
  36. data/test/standard_api/test_app/views/sessions/create.json.jbuilder +1 -0
  37. data/test/standard_api/test_app/views/sessions/create.streamer +3 -0
  38. data/test/standard_api/test_app.rb +12 -1
  39. data/test/standard_api/test_helper.rb +9 -0
  40. metadata +52 -13
@@ -13,23 +13,35 @@ module StandardAPI
13
13
  end
14
14
  end
15
15
 
16
- test '#destroy.json mask' do
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 #current_mask isn't defined by StandardAPI we don't know how to
23
- # test other's implementation of #current_mask. Return and don't test.
24
- return if @controller.method(:current_mask).owner != StandardAPI
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.current_mask[plural_name] = { id: m.id + 1 }
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 mask' do
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 #current_mask isn't defined by StandardAPI we don't know how to
125
- # test other's implementation of #current_mask. Return and don't test.
126
- return if @controller.method(:current_mask).owner != StandardAPI
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.current_mask[plural_name] = { id: m.id }
130
- get :index, format: :json
131
- models = @controller.instance_variable_get("@#{plural_name}")
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 mask' do
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 #current_mask isn't defined by StandardAPI we don't know how to
62
- # test other's implementation of #current_mask. Return and don't test.
63
- return if @controller.method(:current_mask).owner != StandardAPI
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
- @controller.current_mask[plural_name] = { id: m.id + 1 }
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 mask' do
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 #current_mask isn't defined by StandardAPI we don't know how to
141
- # test other's implementation of #current_mask. Return and don't test.
142
- return if @controller.method(:current_mask).owner != StandardAPI
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.current_mask[plural_name] = { id: m.id + 1 }
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
@@ -1,3 +1,3 @@
1
1
  module StandardAPI
2
- VERSION = '6.1.0'
2
+ VERSION = '7.1.0'
3
3
  end
@@ -1,7 +1,8 @@
1
- record.attributes.each do |name, value|
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.to_s }
4
- json.set! name, value
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|
@@ -1,9 +1,10 @@
1
1
  json.object! do
2
2
 
3
- record.attributes.each do |name, value|
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.to_s }
6
- json.set! name, value
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
- json.set! column.name, {
54
- type: json_column_type(column.sql_type),
55
- default: column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil,
56
- primary_key: column.name == model.primary_key,
57
- null: column.null,
58
- array: column.array,
59
- comment: column.comment
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
- json.set! column.name, {
63
- type: json_column_type(column.sql_type),
64
- default: column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil,
65
- primary_key: column.name == model.primary_key,
66
- null: column.null,
67
- array: column.array,
68
- comment: column.comment
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
@@ -19,4 +19,5 @@ require 'standard_api/railtie'
19
19
 
20
20
  module StandardAPI
21
21
  autoload :AccessControlList, 'standard_api/access_control_list'
22
+ autoload :Middleware, 'standard_api/middleware'
22
23
  end
@@ -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
@@ -80,7 +80,7 @@ class HelpersTest < ActionView::TestCase
80
80
  account.expects(:photos_cached_at).returns(t1)
81
81
 
82
82
  assert_equal(
83
- "accounts/#{account.id}/photos-#{t1.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
83
+ "accounts/#{account.id}/photos-#{t1.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
84
84
  association_cache_key(account, :photos, {})
85
85
  )
86
86
 
@@ -88,7 +88,7 @@ class HelpersTest < ActionView::TestCase
88
88
  account.expects(:photos_cached_at).returns(t1)
89
89
  account.expects(:photos_property_cached_at).returns(t2)
90
90
  assert_equal(
91
- "accounts/#{account.id}/photos-2ea683a694a33359514c41435f8f0646-#{t2.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
91
+ "accounts/#{account.id}/photos-2ea683a694a33359514c41435f8f0646-#{t2.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
92
92
  association_cache_key(account, :photos, {property: {}})
93
93
  )
94
94
 
@@ -96,7 +96,7 @@ class HelpersTest < ActionView::TestCase
96
96
  account.expects(:photos_cached_at).returns(t1)
97
97
  account.expects(:photos_property_cached_at).returns(t2)
98
98
  assert_equal(
99
- "accounts/#{account.id}/photos-779c17ef027655fd8c06c3083d2df64b-#{t2.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
99
+ "accounts/#{account.id}/photos-779c17ef027655fd8c06c3083d2df64b-#{t2.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
100
100
  association_cache_key(account, :photos, { "property" => { "order" => { "x" => "desc" }}})
101
101
  )
102
102
 
@@ -105,7 +105,7 @@ class HelpersTest < ActionView::TestCase
105
105
  account.expects(:photos_property_cached_at).returns(t2)
106
106
  account.expects(:photos_agents_cached_at).returns(t3)
107
107
  assert_equal(
108
- "accounts/#{account.id}/photos-abbee2d4535400c162c8dbf14bbef6d5-#{t3.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
108
+ "accounts/#{account.id}/photos-abbee2d4535400c162c8dbf14bbef6d5-#{t3.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
109
109
  association_cache_key(account, :photos, {property: {}, agents: {}})
110
110
  )
111
111
 
@@ -114,7 +114,7 @@ class HelpersTest < ActionView::TestCase
114
114
  account.expects(:photos_property_cached_at).returns(t2)
115
115
  account.expects(:photos_property_agents_cached_at).returns(t3)
116
116
  assert_equal(
117
- "accounts/#{account.id}/photos-0962ae73347c5c605d329eaa25e2be49-#{t3.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
117
+ "accounts/#{account.id}/photos-0962ae73347c5c605d329eaa25e2be49-#{t3.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
118
118
  association_cache_key(account, :photos, {property: {agents: {}}})
119
119
  )
120
120
 
@@ -124,7 +124,7 @@ class HelpersTest < ActionView::TestCase
124
124
  account.expects(:photos_agents_cached_at).returns(t2)
125
125
  account.expects(:photos_property_addresses_cached_at).returns(t3)
126
126
  assert_equal(
127
- "accounts/#{account.id}/photos-00ea6afe3ff68037f8b4dcdb275e2a24-#{t3.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
127
+ "accounts/#{account.id}/photos-00ea6afe3ff68037f8b4dcdb275e2a24-#{t3.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
128
128
  association_cache_key(account, :photos, {property: {addresses: {}}, agents: {}})
129
129
  )
130
130
 
@@ -132,7 +132,7 @@ class HelpersTest < ActionView::TestCase
132
132
  Photo.expects(:column_names).returns(['id', 'cached_at', 'account_cached_at'])
133
133
  photo.expects(:account_cached_at).returns(t1)
134
134
  assert_equal(
135
- "accounts/#{account.id}-#{t1.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
135
+ "accounts/#{account.id}-#{t1.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
136
136
  association_cache_key(photo, :account, {})
137
137
  )
138
138
 
@@ -140,7 +140,7 @@ class HelpersTest < ActionView::TestCase
140
140
  photo.expects(:account_cached_at).returns(t1)
141
141
  photo.expects(:account_photos_cached_at).returns(t2)
142
142
  assert_equal(
143
- "accounts/#{account.id}/07437ce3863467f4cd715ae1ef930f08-#{t2.utc.to_s(ActiveRecord::Base.cache_timestamp_format)}",
143
+ "accounts/#{account.id}/07437ce3863467f4cd715ae1ef930f08-#{t2.utc.to_fs(ActiveRecord::Base.cache_timestamp_format)}",
144
144
  association_cache_key(photo, :account, {photos: {}})
145
145
  )
146
146
  end
@@ -150,6 +150,7 @@ class HelpersTest < ActionView::TestCase
150
150
  assert_equal 'string', json_column_type('character varying(2)')
151
151
  assert_equal 'string', json_column_type('character varying(255)')
152
152
  assert_equal 'datetime', json_column_type('timestamp without time zone')
153
+ assert_equal 'datetime', json_column_type('timestamp(6) without time zone')
153
154
  assert_equal 'datetime', json_column_type('time without time zone')
154
155
  assert_equal 'string', json_column_type('text')
155
156
  assert_equal 'hash', json_column_type('json')