standardapi 1.0.23 → 5.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/standard_api/controller.rb +49 -13
- data/lib/standard_api/helpers.rb +93 -1
- data/lib/standard_api/includes.rb +3 -6
- data/lib/standard_api/middleware/query_encoding.rb +34 -0
- data/lib/standard_api/orders.rb +24 -12
- data/lib/standard_api/railtie.rb +1 -0
- data/lib/standard_api/route_helpers.rb +26 -0
- data/lib/standard_api/test_case/calculate_tests.rb +8 -3
- data/lib/standard_api/test_case/create_tests.rb +22 -6
- data/lib/standard_api/test_case/destroy_tests.rb +2 -2
- data/lib/standard_api/test_case/index_tests.rb +9 -9
- data/lib/standard_api/test_case/new_tests.rb +14 -0
- data/lib/standard_api/test_case/show_tests.rb +3 -4
- data/lib/standard_api/test_case/update_tests.rb +37 -9
- data/lib/standard_api/test_case.rb +4 -4
- data/lib/standard_api/views/application/_record.json.jbuilder +34 -26
- data/lib/standard_api/views/application/index.json.jbuilder +12 -1
- data/lib/standard_api/views/application/new.json.jbuilder +1 -0
- data/lib/standard_api/views/application/schema.json.jbuilder +1 -1
- data/lib/standard_api/views/application/show.json.jbuilder +0 -1
- data/lib/standard_api.rb +1 -1
- metadata +49 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32b4ca6314bc038faf8b73560d327096f4c4bf53
|
4
|
+
data.tar.gz: 1162cb994c7921a7ffc4eea033a40b0e5f4f50b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: deaa898296ded369ca9c9b2289eaab9c803977d9f51f5283bf20d546da33b41e9d6fa2c7750195a9c438a87b59434f29fd0eca79421bce83db6774244276456c
|
7
|
+
data.tar.gz: eaeb860e977eee866a9f98ce6ef4b10f697a95a2a6d3e33a286fc390e45102fc287b3139c14ab1a6868b04a115deacabe745c15286f11de76ab86922f6a440c8
|
@@ -2,20 +2,20 @@ module StandardAPI
|
|
2
2
|
module Controller
|
3
3
|
|
4
4
|
def self.included(klass)
|
5
|
-
klass.hide_action :current_mask
|
6
5
|
klass.helper_method :includes, :orders, :model
|
7
6
|
klass.append_view_path(File.join(File.dirname(__FILE__), 'views'))
|
8
7
|
klass.extend(ClassMethods)
|
9
8
|
end
|
10
|
-
|
9
|
+
|
11
10
|
def ping
|
12
|
-
render :
|
11
|
+
render plain: 'pong'
|
13
12
|
end
|
14
13
|
|
15
14
|
def tables
|
16
15
|
controllers = Dir[Rails.root.join('app/controllers/*_controller.rb')].map{ |path| path.match(/(\w+)_controller.rb/)[1].camelize+"Controller" }.map(&:safe_constantize)
|
17
16
|
controllers.select! { |c| c.ancestors.include?(self.class) && c != self.class }
|
18
|
-
controllers.map!(&:model).compact
|
17
|
+
controllers.map!(&:model).compact!
|
18
|
+
controllers.map!(&:table_name)
|
19
19
|
|
20
20
|
render json: controllers
|
21
21
|
end
|
@@ -39,19 +39,43 @@ module StandardAPI
|
|
39
39
|
instance_variable_set("@#{model.model_name.singular}", resources.find(params[:id]))
|
40
40
|
end
|
41
41
|
|
42
|
+
def new
|
43
|
+
instance_variable_set("@#{model.model_name.singular}", model.new) if model
|
44
|
+
end
|
45
|
+
|
42
46
|
def create
|
43
|
-
|
44
|
-
|
47
|
+
record = model.new(model_params)
|
48
|
+
instance_variable_set("@#{model.model_name.singular}", record)
|
49
|
+
|
50
|
+
if record.save
|
51
|
+
if request.format == :html
|
52
|
+
redirect_to record
|
53
|
+
else
|
54
|
+
render :show, status: :created
|
55
|
+
end
|
56
|
+
else
|
57
|
+
render :show, status: :bad_request
|
58
|
+
end
|
45
59
|
end
|
46
60
|
|
47
61
|
def update
|
48
|
-
|
49
|
-
|
62
|
+
record = resources.find(params[:id])
|
63
|
+
instance_variable_set("@#{model.model_name.singular}", record)
|
64
|
+
|
65
|
+
if record.update_attributes(model_params)
|
66
|
+
if request.format == :html
|
67
|
+
redirect_to record
|
68
|
+
else
|
69
|
+
render :show, status: :ok
|
70
|
+
end
|
71
|
+
else
|
72
|
+
render :show, status: :bad_request
|
73
|
+
end
|
50
74
|
end
|
51
75
|
|
52
76
|
def destroy
|
53
77
|
resources.find(params[:id]).destroy!
|
54
|
-
|
78
|
+
head :no_content
|
55
79
|
end
|
56
80
|
|
57
81
|
# Override if you want to support masking
|
@@ -75,15 +99,27 @@ module StandardAPI
|
|
75
99
|
end
|
76
100
|
|
77
101
|
def model_params
|
78
|
-
|
102
|
+
if self.respond_to?("#{model.model_name.singular}_params", true)
|
103
|
+
params.require(model.model_name.singular).permit(self.send("#{model.model_name.singular}_params"))
|
104
|
+
else
|
105
|
+
[]
|
106
|
+
end
|
79
107
|
end
|
80
108
|
|
81
109
|
def model_includes
|
82
|
-
self.
|
110
|
+
if self.respond_to?("#{model.model_name.singular}_includes", true)
|
111
|
+
self.send "#{model.model_name.singular}_includes"
|
112
|
+
else
|
113
|
+
[]
|
114
|
+
end
|
83
115
|
end
|
84
116
|
|
85
117
|
def model_orders
|
86
|
-
self.
|
118
|
+
if self.respond_to?("#{model.model_name.singular}_orders", true)
|
119
|
+
self.send "#{model.model_name.singular}_orders"
|
120
|
+
else
|
121
|
+
[]
|
122
|
+
end
|
87
123
|
end
|
88
124
|
|
89
125
|
def excludes_for(klass)
|
@@ -139,4 +175,4 @@ module StandardAPI
|
|
139
175
|
end
|
140
176
|
|
141
177
|
end
|
142
|
-
end
|
178
|
+
end
|
data/lib/standard_api/helpers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module StandardAPI
|
2
2
|
module Helpers
|
3
|
-
|
3
|
+
|
4
4
|
def model_partial(record)
|
5
5
|
if lookup_context.exists?(record.model_name.element, record.model_name.plural, true)
|
6
6
|
[record.model_name.plural, record.model_name.element].join('/')
|
@@ -8,6 +8,98 @@ module StandardAPI
|
|
8
8
|
'application/record'
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
def can_cache?(klass, includes)
|
13
|
+
cache_columns = ['cached_at'] + cached_at_columns_for_includes(includes)
|
14
|
+
if (cache_columns - klass.column_names).empty?
|
15
|
+
true
|
16
|
+
else
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cache_key(record, includes)
|
22
|
+
timestamp_keys = ['cached_at'] + cached_at_columns_for_includes(includes)
|
23
|
+
if includes.empty?
|
24
|
+
record.cache_key(*timestamp_keys)
|
25
|
+
else
|
26
|
+
timestamp = record.send(:max_updated_column_timestamp, timestamp_keys)
|
27
|
+
"#{record.model_name.cache_key}/#{record.id}-#{digest_hash(sort_hash(includes))}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_cache_relation?(klass, relation, subincludes)
|
32
|
+
cache_columns = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
|
33
|
+
if (cache_columns - klass.column_names).empty?
|
34
|
+
true
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def association_cache_key(record, relation, subincludes)
|
41
|
+
timestamp = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
|
42
|
+
timestamp.map! { |col| record.send(col) }
|
43
|
+
timestamp = timestamp.max
|
44
|
+
|
45
|
+
case association = record.class.reflect_on_association(relation)
|
46
|
+
when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::HasOneReflection, ActiveRecord::Reflection::ThroughReflection
|
47
|
+
"#{record.model_name.cache_key}/#{record.id}/#{includes_to_cache_key(relation, subincludes)}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
|
48
|
+
when ActiveRecord::Reflection::BelongsToReflection
|
49
|
+
klass = association.options[:polymorphic] ? record.send(association.foreign_type).constantize : association.klass
|
50
|
+
if subincludes.empty?
|
51
|
+
"#{klass.model_name.cache_key}/#{record.send(association.foreign_key)}-#{timestamp.utc.to_s(klass.cache_timestamp_format)}"
|
52
|
+
else
|
53
|
+
"#{klass.model_name.cache_key}/#{record.send(association.foreign_key)}/#{digest_hash(sort_hash(subincludes))}-#{timestamp.utc.to_s(klass.cache_timestamp_format)}"
|
54
|
+
end
|
55
|
+
else
|
56
|
+
raise ArgumentError, 'Unkown association type'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def cached_at_columns_for_includes(includes)
|
61
|
+
includes.select{|k,v| ![:where, :limit, :order].include?(k.to_sym) }.map { |k, v|
|
62
|
+
["#{k}_cached_at"] + cached_at_columns_for_includes(v).map{|v| "#{k}_#{v}"}
|
63
|
+
}.flatten
|
64
|
+
end
|
65
|
+
|
66
|
+
def includes_to_cache_key(relation, subincludes)
|
67
|
+
if subincludes.empty?
|
68
|
+
relation.to_s
|
69
|
+
else
|
70
|
+
"#{relation}-#{digest_hash(sort_hash(subincludes))}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def sort_hash(hash)
|
75
|
+
hash.keys.sort.reduce({}) do |seed, key|
|
76
|
+
if seed[key].is_a?(Hash)
|
77
|
+
seed[key] = sort_hash(hash[key])
|
78
|
+
else
|
79
|
+
seed[key] = hash[key]
|
80
|
+
end
|
81
|
+
seed
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def digest_hash(*hashes)
|
86
|
+
hashes.compact!
|
87
|
+
hashes.map! { |h| sort_hash(h) }
|
88
|
+
|
89
|
+
digest = Digest::MD5.new()
|
90
|
+
hashes.each do |hash|
|
91
|
+
hash.each do |key, value|
|
92
|
+
digest << key.to_s
|
93
|
+
if value.is_a?(Hash)
|
94
|
+
digest << digest_hash(value)
|
95
|
+
else
|
96
|
+
digest << value.to_s
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
digest.hexdigest
|
102
|
+
end
|
11
103
|
|
12
104
|
end
|
13
105
|
end
|
@@ -15,10 +15,10 @@ module StandardAPI
|
|
15
15
|
case includes
|
16
16
|
when Array
|
17
17
|
includes.flatten.compact.each { |v| normalized.merge!(normalize(v)) }
|
18
|
-
when Hash
|
18
|
+
when Hash, ActionController::Parameters
|
19
19
|
includes.each_pair do |k, v|
|
20
20
|
if ['where', 'order'].include?(k.to_s) # Where and order are not normalized
|
21
|
-
normalized[k] = v
|
21
|
+
normalized[k] = v.to_h
|
22
22
|
else
|
23
23
|
normalized[k] = normalize(v)
|
24
24
|
end
|
@@ -55,10 +55,7 @@ module StandardAPI
|
|
55
55
|
permitted[k] = sanitize(v, permit[k] || {}, true)
|
56
56
|
else
|
57
57
|
if [:raise, nil].include?(Rails.configuration.try(:action_on_unpermitted_includes))
|
58
|
-
raise
|
59
|
-
Invalid Include: #{k}"
|
60
|
-
Set config.action_on_unpermitted_includes = :warm to log instead of raise
|
61
|
-
ERR
|
58
|
+
raise ActionController::UnpermittedParameters.new([k])
|
62
59
|
else
|
63
60
|
Rails.logger.try(:warn, "Invalid Include: #{k}")
|
64
61
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'msgpack'
|
2
|
+
|
3
|
+
# QueryEncoding middleware intercepts and parsing the query sting as MessagePack
|
4
|
+
# if the `Query-Encoding` header is set to `application/msgpack`
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# require 'standard_api/middleware/query_encoding'
|
9
|
+
#
|
10
|
+
# And in the Rails config
|
11
|
+
#
|
12
|
+
# config.middleware.insert_after Rack::MethodOverride, StandardAPI::Middleware::QueryEncoding
|
13
|
+
module StandardAPI
|
14
|
+
module Middleware
|
15
|
+
class QueryEncoding
|
16
|
+
MSGPACK_MIME_TYPE = "application/msgpack".freeze
|
17
|
+
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_QUERY_ENCODING".freeze
|
18
|
+
|
19
|
+
def initialize(app)
|
20
|
+
@app = app
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
if !env[Rack::QUERY_STRING].empty? && env[HTTP_METHOD_OVERRIDE_HEADER] == MSGPACK_MIME_TYPE
|
25
|
+
env[Rack::RACK_REQUEST_QUERY_STRING] = env[Rack::QUERY_STRING]
|
26
|
+
env[Rack::RACK_REQUEST_QUERY_HASH] = MessagePack.unpack(CGI.unescape(env[Rack::QUERY_STRING]))
|
27
|
+
end
|
28
|
+
|
29
|
+
@app.call(env)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/standard_api/orders.rb
CHANGED
@@ -9,37 +9,49 @@ module StandardAPI
|
|
9
9
|
permitted = []
|
10
10
|
|
11
11
|
case orders
|
12
|
-
when Hash
|
12
|
+
when Hash, ActionController::Parameters
|
13
13
|
orders.each do |key, value|
|
14
14
|
if key.to_s.count('.') == 1
|
15
15
|
key2, key3 = *key.to_s.split('.')
|
16
|
-
permitted
|
16
|
+
permitted << sanitize({key2.to_sym => { key3.to_sym => value } }, permit)
|
17
17
|
elsif permit.include?(key.to_s)
|
18
|
-
value = value.symbolize_keys if value.is_a?(Hash)
|
19
|
-
permitted
|
20
|
-
elsif permit.find { |x| x.is_a?(Hash) && x.has_key?(key.to_s) }
|
21
|
-
subpermit = permit.find { |x| x.is_a?(Hash) && x.has_key?(key.to_s) }[key.to_s]
|
18
|
+
value = value.symbolize_keys if value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
|
19
|
+
permitted << { key.to_sym => value }
|
20
|
+
elsif permit.find { |x| (x.is_a?(Hash) || x.is_a?(ActionController::Parameters)) && x.has_key?(key.to_s) }
|
21
|
+
subpermit = permit.find { |x| (x.is_a?(Hash) || x.is_a?(ActionController::Parameters)) && x.has_key?(key.to_s) }[key.to_s]
|
22
22
|
sanitized_value = sanitize(value, subpermit)
|
23
|
-
permitted
|
23
|
+
permitted << { key.to_sym => sanitized_value }
|
24
24
|
else
|
25
|
-
raise(
|
25
|
+
raise(ActionController::UnpermittedParameters.new([orders]))
|
26
26
|
end
|
27
27
|
end
|
28
28
|
when Array
|
29
|
-
orders.each
|
29
|
+
orders.each do |order|
|
30
|
+
order = sanitize(order, permit)
|
31
|
+
if order.is_a?(Array)
|
32
|
+
permitted += order
|
33
|
+
else
|
34
|
+
permitted << order
|
35
|
+
end
|
36
|
+
end
|
30
37
|
else
|
31
|
-
|
32
38
|
if orders.to_s.count('.') == 1
|
33
39
|
key, value = *orders.to_s.split('.')
|
34
40
|
permitted = sanitize({key.to_sym => value.to_sym}, permit)
|
35
41
|
elsif permit.include?(orders.to_s)
|
36
42
|
permitted = orders
|
37
43
|
else
|
38
|
-
raise(
|
44
|
+
raise(ActionController::UnpermittedParameters.new([orders]))
|
39
45
|
end
|
40
46
|
end
|
41
47
|
|
42
|
-
permitted
|
48
|
+
if permitted.is_a?(Array) && permitted.length == 1
|
49
|
+
permitted.first
|
50
|
+
else
|
51
|
+
permitted
|
52
|
+
end
|
53
|
+
|
54
|
+
# permitted
|
43
55
|
end
|
44
56
|
|
45
57
|
end
|
data/lib/standard_api/railtie.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
module StandardAPI
|
2
|
+
module RouteHelpers
|
3
|
+
|
4
|
+
# Shorthand for adding resources.
|
5
|
+
#
|
6
|
+
# For example
|
7
|
+
#
|
8
|
+
# standard_resources :views
|
9
|
+
#
|
10
|
+
# Is equivilent to:
|
11
|
+
#
|
12
|
+
# resources :api_keys do
|
13
|
+
# get :schema, on: :collection
|
14
|
+
# get :calculate, on: :collection
|
15
|
+
# end
|
16
|
+
def standard_resources(*resources, &block)
|
17
|
+
options = resources.extract_options!.dup
|
18
|
+
|
19
|
+
resources(*resources, options) do
|
20
|
+
get :schema, on: :collection
|
21
|
+
get :calculate, on: :collection
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -7,7 +7,7 @@ module StandardAPI
|
|
7
7
|
m = create_model
|
8
8
|
selects = [{ count: :id}, { maximum: :id }, { minimum: :id }, { average: :id }]
|
9
9
|
|
10
|
-
get :calculate, select: selects, format:
|
10
|
+
get :calculate, params: {select: selects}, format: :json
|
11
11
|
assert_response :ok
|
12
12
|
assert_equal [[model.count(:id), model.maximum(:id), model.minimum(:id), model.average(:id).to_f]], assigns(:calculations)
|
13
13
|
end
|
@@ -19,9 +19,14 @@ module StandardAPI
|
|
19
19
|
selects = [{ count: :id}, { maximum: :id }, { minimum: :id }, { average: :id }]
|
20
20
|
predicate = { id: { gt: m1.id } }
|
21
21
|
|
22
|
-
get :calculate, where: predicate, select: selects, format:
|
22
|
+
get :calculate, params: {where: predicate, select: selects}, format: :json
|
23
23
|
assert_response :ok
|
24
|
-
assert_equal [[
|
24
|
+
assert_equal [[
|
25
|
+
model.filter(predicate).count(:id),
|
26
|
+
model.filter(predicate).maximum(:id),
|
27
|
+
model.filter(predicate).minimum(:id),
|
28
|
+
model.filter(predicate).average(:id).to_f
|
29
|
+
]], assigns(:calculations)
|
25
30
|
end
|
26
31
|
|
27
32
|
test '#calculate.json mask' do
|
@@ -3,12 +3,17 @@ module StandardAPI
|
|
3
3
|
module CreateTests
|
4
4
|
extend ActiveSupport::Testing::Declarative
|
5
5
|
|
6
|
+
def setup
|
7
|
+
@request.content_type="application/json"
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
6
11
|
test '#create.json' do
|
7
12
|
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
8
13
|
create_webmocks(attrs)
|
9
14
|
|
10
15
|
assert_difference("#{model.name}.count") do
|
11
|
-
post :create, singular_name => attrs, :
|
16
|
+
post :create, params: {singular_name => attrs}, format: :json
|
12
17
|
assert_response :created
|
13
18
|
assert assigns(singular_name)
|
14
19
|
|
@@ -18,7 +23,11 @@ module StandardAPI
|
|
18
23
|
m = assigns(singular_name)
|
19
24
|
view_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
|
20
25
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
21
|
-
|
26
|
+
if value.is_a?(BigDecimal)
|
27
|
+
assert_equal normalize_to_json(m, key, attrs[key.to_sym]).to_s.to_f, json[key.to_s].to_s.to_f, message
|
28
|
+
else
|
29
|
+
assert_equal normalize_to_json(m, key, attrs[key.to_sym]), json[key.to_s], message
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
@@ -28,13 +37,12 @@ module StandardAPI
|
|
28
37
|
create_webmocks(attrs)
|
29
38
|
|
30
39
|
assert_difference("#{model.name}.count") do
|
31
|
-
post :create, singular_name => attrs, :
|
40
|
+
post :create, params: {singular_name => attrs}, format: :json
|
32
41
|
assert_response :created
|
33
42
|
assert assigns(singular_name)
|
34
43
|
|
35
44
|
json = JSON.parse(response.body)
|
36
45
|
assert json.is_a?(Hash)
|
37
|
-
|
38
46
|
m = assigns(singular_name).reload
|
39
47
|
view_attributes(m).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
|
40
48
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
@@ -44,11 +52,19 @@ module StandardAPI
|
|
44
52
|
end
|
45
53
|
|
46
54
|
test '#create.json with invalid attributes' do
|
55
|
+
trait = FactoryGirl.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
56
|
+
|
57
|
+
if !trait
|
58
|
+
Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
|
59
|
+
warn("No invalid trait for #{model.name}. Skipping invalid tests")
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
47
63
|
attrs = attributes_for(singular_name, :invalid).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
48
64
|
create_webmocks(attrs)
|
49
65
|
|
50
66
|
assert_difference("#{model.name}.count", 0) do
|
51
|
-
post :create, singular_name => attrs, :
|
67
|
+
post :create, params: {singular_name => attrs}, format: :json
|
52
68
|
assert_response :bad_request
|
53
69
|
json = JSON.parse(response.body)
|
54
70
|
assert json.is_a?(Hash)
|
@@ -62,7 +78,7 @@ module StandardAPI
|
|
62
78
|
create_webmocks(attrs)
|
63
79
|
|
64
80
|
assert_difference("#{model.name}.count") do
|
65
|
-
post :create, singular_name => attrs, include
|
81
|
+
post :create, params: {singular_name => attrs, :include => includes}, format: :json
|
66
82
|
assert_response :created
|
67
83
|
assert assigns(singular_name)
|
68
84
|
|
@@ -7,7 +7,7 @@ module StandardAPI
|
|
7
7
|
m = create_model
|
8
8
|
|
9
9
|
assert_difference("#{model.name}.count", -1) do
|
10
|
-
delete :destroy, id: m.id, format:
|
10
|
+
delete :destroy, params: { id: m.id }, format: :json
|
11
11
|
assert_response :no_content
|
12
12
|
assert_equal '', response.body
|
13
13
|
end
|
@@ -21,7 +21,7 @@ module StandardAPI
|
|
21
21
|
m = create_model
|
22
22
|
@controller.current_mask[plural_name] = { id: m.id + 1 }
|
23
23
|
assert_raises(ActiveRecord::RecordNotFound) do
|
24
|
-
delete :destroy, id: m.id, format:
|
24
|
+
delete :destroy, params: { id: m.id }, format: :json
|
25
25
|
end
|
26
26
|
@controller.current_mask.delete(plural_name)
|
27
27
|
end
|
@@ -4,41 +4,41 @@ module StandardAPI
|
|
4
4
|
extend ActiveSupport::Testing::Declarative
|
5
5
|
|
6
6
|
test '#index.json' do
|
7
|
-
get :index, format:
|
7
|
+
get :index, format: :json
|
8
8
|
assert_response :ok
|
9
|
-
assert_template :index
|
10
9
|
assert_equal model.all.map(&:id).sort, assigns(plural_name).map(&:id).sort
|
11
10
|
assert JSON.parse(response.body).is_a?(Array)
|
12
11
|
end
|
13
12
|
|
14
13
|
test '#index.json params[:limit]' do
|
15
|
-
get :index, limit: 1, format:
|
14
|
+
get :index, params: { limit: 1 }, format: :json
|
16
15
|
assert_equal model.limit(1).to_sql, assigns(plural_name).to_sql
|
17
16
|
end
|
18
17
|
|
19
18
|
test '#index.json params[:where]' do
|
20
19
|
m = create_model
|
21
|
-
|
20
|
+
|
21
|
+
get :index, params: { where: { id: m.id } }, format: :json
|
22
22
|
assert_equal [m], assigns(plural_name)
|
23
23
|
end
|
24
24
|
|
25
25
|
test '#index.json params[:order]' do
|
26
26
|
orders.each do |order|
|
27
27
|
@controller.instance_variable_set('@orders', nil) # Hack for dealing with caching / multiple request per controller life
|
28
|
-
get :index, order: order, format:
|
28
|
+
get :index, params: { order: order }, format: :json
|
29
29
|
assert_equal model.sort(order).to_sql, assigns(plural_name).to_sql
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
test '#index.json params[:offset]' do
|
34
|
-
get :index, offset: 13, format:
|
34
|
+
get :index, params: { offset: 13 }, format: :json
|
35
35
|
assert_equal model.offset(13).to_sql, assigns(plural_name).to_sql
|
36
36
|
end
|
37
37
|
|
38
38
|
test '#index.json params[:include]' do
|
39
39
|
travel_to Time.now do
|
40
40
|
create_model
|
41
|
-
get :index, include: includes, format:
|
41
|
+
get :index, params: { include: includes }, format: :json
|
42
42
|
|
43
43
|
json = JSON.parse(response.body)[0]
|
44
44
|
assert json.is_a?(Hash)
|
@@ -67,7 +67,7 @@ module StandardAPI
|
|
67
67
|
|
68
68
|
view_attributes(m).each do |key, value|
|
69
69
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
70
|
-
assert_equal m_json[key.to_s], normalize_to_json(m, key, value)
|
70
|
+
assert_equal m_json[key.to_s], normalize_to_json(m, key, value), message
|
71
71
|
end
|
72
72
|
|
73
73
|
end
|
@@ -82,7 +82,7 @@ module StandardAPI
|
|
82
82
|
|
83
83
|
m = create_model
|
84
84
|
@controller.current_mask[plural_name] = { id: m.id }
|
85
|
-
get :index, format:
|
85
|
+
get :index, format: :json
|
86
86
|
assert_equal model.where(id: m.id).to_sql, assigns(plural_name).to_sql
|
87
87
|
@controller.current_mask.delete(plural_name)
|
88
88
|
end
|
@@ -6,16 +6,15 @@ module StandardAPI
|
|
6
6
|
test '#show.json' do
|
7
7
|
m = create_model
|
8
8
|
|
9
|
-
get :show, id: m.id, format:
|
9
|
+
get :show, params: {id: m.id}, format: :json
|
10
10
|
assert_response :ok
|
11
|
-
assert_template :show
|
12
11
|
assert_equal m, assigns(singular_name)
|
13
12
|
assert JSON.parse(response.body).is_a?(Hash)
|
14
13
|
end
|
15
14
|
|
16
15
|
test '#show.json params[:include]' do
|
17
16
|
m = create_model
|
18
|
-
get :show, id: m.id, include: includes, format:
|
17
|
+
get :show, params: {id: m.id, include: includes}, format: :json
|
19
18
|
|
20
19
|
json = JSON.parse(response.body)
|
21
20
|
includes.each do |included|
|
@@ -56,7 +55,7 @@ module StandardAPI
|
|
56
55
|
m = create_model
|
57
56
|
@controller.current_mask[plural_name] = { id: m.id + 1 }
|
58
57
|
assert_raises(ActiveRecord::RecordNotFound) do
|
59
|
-
get :show, id: m.id, format:
|
58
|
+
get :show, params: {id: m.id}, format: :json
|
60
59
|
end
|
61
60
|
@controller.current_mask.delete(plural_name)
|
62
61
|
end
|
@@ -3,26 +3,46 @@ module StandardAPI
|
|
3
3
|
module UpdateTests
|
4
4
|
extend ActiveSupport::Testing::Declarative
|
5
5
|
|
6
|
+
def setup
|
7
|
+
@request.content_type="application/json"
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
6
11
|
test '#update.json' do
|
7
12
|
m = create_model
|
8
13
|
attrs = attributes_for(singular_name).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
9
14
|
create_webmocks(attrs)
|
10
15
|
|
11
|
-
put :update,
|
12
|
-
assert_response :ok
|
16
|
+
put :update, params: {:id => m.id, singular_name => attrs}, format: :json
|
17
|
+
assert_response :ok, "Updating #{m.class.name} with #{attrs.inspect}"
|
13
18
|
|
14
19
|
view_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
|
15
20
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
16
|
-
|
21
|
+
if value.is_a?(BigDecimal)
|
22
|
+
assert_equal normalize_attribute(m, key, attrs[key.to_sym]).to_s.to_f, value.to_s.to_f, message
|
23
|
+
else
|
24
|
+
assert_equal normalize_attribute(m, key, attrs[key.to_sym]), value, message
|
25
|
+
end
|
17
26
|
end
|
18
27
|
assert JSON.parse(@response.body).is_a?(Hash)
|
19
28
|
end
|
20
29
|
|
30
|
+
test '#update.html redirects to #show.html' do
|
31
|
+
return if @controller.method(:update).owner != StandardAPI
|
32
|
+
|
33
|
+
m = create_model
|
34
|
+
attrs = attributes_for(singular_name).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
35
|
+
create_webmocks(attrs)
|
36
|
+
|
37
|
+
put :update, params: {:id => m.id, singular_name => attrs}, format: :html
|
38
|
+
assert_redirected_to m
|
39
|
+
end
|
40
|
+
|
21
41
|
test '#update.json with nested attributes' do
|
22
42
|
m = create_model
|
23
43
|
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
24
44
|
create_webmocks(attrs)
|
25
|
-
put :update,
|
45
|
+
put :update, params: {:id => m.id, singular_name => attrs}, format: :json
|
26
46
|
assert_response :ok
|
27
47
|
|
28
48
|
# (m.attribute_names & attrs.keys.map(&:to_s)).each do |test_key|
|
@@ -34,12 +54,20 @@ module StandardAPI
|
|
34
54
|
end
|
35
55
|
|
36
56
|
test '#update.json with invalid attributes' do
|
57
|
+
trait = FactoryGirl.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
58
|
+
|
59
|
+
if !trait
|
60
|
+
Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
|
61
|
+
warn("No invalid trait for #{model.name}. Skipping invalid tests")
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
37
65
|
m = create_model
|
38
66
|
attrs = attributes_for(singular_name, :invalid).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
39
67
|
create_webmocks(attrs)
|
40
68
|
|
41
|
-
put :update,
|
42
|
-
assert_response :bad_request
|
69
|
+
put :update, params: {:id => m.id, singular_name => attrs}, format: :json
|
70
|
+
assert_response :bad_request, "Updating #{m.class.name} with invalid attributes #{attrs.inspect}"
|
43
71
|
assert JSON.parse(@response.body)['errors']
|
44
72
|
end
|
45
73
|
|
@@ -49,7 +77,7 @@ module StandardAPI
|
|
49
77
|
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k) }
|
50
78
|
create_webmocks(attrs)
|
51
79
|
|
52
|
-
put :update,
|
80
|
+
put :update, params: {:id => m.id, :include => includes, singular_name => attrs}, format: :json
|
53
81
|
|
54
82
|
json = JSON.parse(response.body)
|
55
83
|
includes.each do |included|
|
@@ -75,7 +103,7 @@ module StandardAPI
|
|
75
103
|
|
76
104
|
view_attributes(m).each do |key, value|
|
77
105
|
message = "Model / Attribute: #{m.class.name}##{key}"
|
78
|
-
assert_equal m_json[key.to_s], normalize_to_json(m, key, value)
|
106
|
+
assert_equal m_json[key.to_s], normalize_to_json(m, key, value), message
|
79
107
|
end
|
80
108
|
|
81
109
|
end
|
@@ -91,7 +119,7 @@ module StandardAPI
|
|
91
119
|
m = create_model
|
92
120
|
@controller.current_mask[plural_name] = { id: m.id + 1 }
|
93
121
|
assert_raises(ActiveRecord::RecordNotFound) do
|
94
|
-
put :update, id: m.id, format: 'json'
|
122
|
+
put :update, params: {id: m.id}, format: 'json'
|
95
123
|
end
|
96
124
|
@controller.current_mask.delete(plural_name)
|
97
125
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/test_case'
|
2
2
|
|
3
3
|
require File.expand_path(File.join(__FILE__, '../test_case/calculate_tests'))
|
4
|
+
require File.expand_path(File.join(__FILE__, '../test_case/new_tests'))
|
4
5
|
require File.expand_path(File.join(__FILE__, '../test_case/create_tests'))
|
5
6
|
require File.expand_path(File.join(__FILE__, '../test_case/destroy_tests'))
|
6
7
|
require File.expand_path(File.join(__FILE__, '../test_case/index_tests'))
|
@@ -78,12 +79,11 @@ module StandardAPI::TestCase
|
|
78
79
|
|
79
80
|
def normalize_to_json(record, attribute, value)
|
80
81
|
value = normalize_attribute(record, attribute, value)
|
81
|
-
|
82
82
|
return nil if value.nil?
|
83
83
|
|
84
|
-
if model.
|
84
|
+
if model.columns_hash[attribute].is_a?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Decimal)
|
85
85
|
"#{value.to_f}"
|
86
|
-
elsif model.
|
86
|
+
elsif value.is_a?(DateTime) #model.columns_hash[attribute].is_a?(ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter)
|
87
87
|
value.in_time_zone.as_json
|
88
88
|
else
|
89
89
|
value.as_json
|
@@ -111,7 +111,7 @@ module StandardAPI::TestCase
|
|
111
111
|
value = m.send(filter[0])
|
112
112
|
|
113
113
|
assert_predicate = -> (predicate) {
|
114
|
-
get :index, where: predicate, format: 'json'
|
114
|
+
get :index, params: {where: predicate}, format: 'json'
|
115
115
|
assert_equal model.filter(predicate).to_sql, assigns(plural_name).to_sql
|
116
116
|
}
|
117
117
|
|
@@ -5,47 +5,55 @@ record.attributes.each do |name, value|
|
|
5
5
|
end
|
6
6
|
|
7
7
|
includes.each do |inc, subinc|
|
8
|
-
next if [
|
9
|
-
|
10
|
-
association = record.class.reflect_on_association(inc)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if collection
|
8
|
+
next if [:where, :order, :limit].include?(inc.to_sym)
|
9
|
+
|
10
|
+
case association = record.class.reflect_on_association(inc)
|
11
|
+
when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::ThroughReflection
|
12
|
+
can_cache = can_cache_relation?(record.class, inc, subinc)
|
13
|
+
json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
|
15
14
|
partial = model_partial(association.klass)
|
16
15
|
json.set! inc do
|
17
|
-
json.array! record.send(inc), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
|
16
|
+
json.array! record.send(inc).filter(subinc[:where]).limit(subinc[:limit]).sort(subinc[:order]), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
|
18
17
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
end
|
19
|
+
|
20
|
+
when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
|
21
|
+
can_cache = can_cache_relation?(record.class, inc, subinc)
|
22
|
+
if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
23
|
+
can_cache = can_cache && !record.send(association.foreign_key).nil?
|
24
|
+
end
|
25
|
+
json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
|
26
|
+
value = record.send(inc)
|
27
|
+
if value.nil?
|
22
28
|
json.set! inc, nil
|
23
29
|
else
|
24
|
-
partial = model_partial(
|
30
|
+
partial = model_partial(value)
|
25
31
|
json.set! inc do
|
26
|
-
json.partial! partial, partial.split('/').last.to_sym =>
|
32
|
+
json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
30
|
-
|
36
|
+
|
31
37
|
else
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
if record.respond_to?(inc)
|
39
|
+
value = record.send(inc)
|
40
|
+
if value.nil?
|
41
|
+
json.set! inc, nil
|
42
|
+
elsif value.is_a?(ActiveModel::Model)
|
43
|
+
json.set! inc do
|
44
|
+
partial = model_partial(value)
|
45
|
+
json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
|
46
|
+
end
|
47
|
+
else
|
48
|
+
json.set! inc, value.as_json
|
39
49
|
end
|
40
|
-
else
|
41
|
-
# TODO: Test
|
42
|
-
json.set! inc, record.send(inc).as_json
|
43
50
|
end
|
44
|
-
|
45
51
|
end
|
46
52
|
|
47
53
|
end
|
48
54
|
|
49
55
|
if !record.errors.blank?
|
50
|
-
|
56
|
+
errs = record.errors.to_hash
|
57
|
+
errs.default_proc = nil
|
58
|
+
json.set! 'errors', errs
|
51
59
|
end
|
@@ -1 +1,12 @@
|
|
1
|
-
|
1
|
+
if !includes.empty? && can_cache?(model, includes)
|
2
|
+
partial = model_partial(model)
|
3
|
+
record_name = partial.split('/').last.to_sym
|
4
|
+
locals = { record_name => nil, :includes => includes}
|
5
|
+
|
6
|
+
json.cache_collection! instance_variable_get("@#{model.model_name.plural}"), key: proc {|record| cache_key(record, includes) } do |record|
|
7
|
+
locals[record_name] = record
|
8
|
+
json.partial! partial, locals
|
9
|
+
end
|
10
|
+
else
|
11
|
+
json.array! instance_variable_get("@#{model.model_name.plural}"), partial: model_partial(model), as: model_partial(model).split('/').last, includes: includes
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! model_partial(model), model_partial(model).split('/').last.to_sym => instance_variable_get("@#{model.model_name.singular}"), includes: includes
|
data/lib/standard_api.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standardapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Bracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.0.0.rc1
|
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:
|
26
|
+
version: 5.0.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 5.0.0.rc1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 5.0.0.rc1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: actionpack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 5.0.0.rc1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 5.0.0.rc1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: activerecord-sort
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.0.0.rc1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.0.0.rc1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activerecord-filter
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
75
|
+
version: 5.0.0.rc1
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
82
|
+
version: 5.0.0.rc1
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: jbuilder
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +206,20 @@ dependencies:
|
|
192
206
|
- - ">="
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: mocha
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
195
223
|
description: StandardAPI makes it easy to expose a query interface for your Rails
|
196
224
|
models
|
197
225
|
email:
|
@@ -206,18 +234,22 @@ files:
|
|
206
234
|
- lib/standard_api/controller.rb
|
207
235
|
- lib/standard_api/helpers.rb
|
208
236
|
- lib/standard_api/includes.rb
|
237
|
+
- lib/standard_api/middleware/query_encoding.rb
|
209
238
|
- lib/standard_api/orders.rb
|
210
239
|
- lib/standard_api/railtie.rb
|
240
|
+
- lib/standard_api/route_helpers.rb
|
211
241
|
- lib/standard_api/test_case.rb
|
212
242
|
- lib/standard_api/test_case/calculate_tests.rb
|
213
243
|
- lib/standard_api/test_case/create_tests.rb
|
214
244
|
- lib/standard_api/test_case/destroy_tests.rb
|
215
245
|
- lib/standard_api/test_case/index_tests.rb
|
246
|
+
- lib/standard_api/test_case/new_tests.rb
|
216
247
|
- lib/standard_api/test_case/schema_test.rb
|
217
248
|
- lib/standard_api/test_case/show_tests.rb
|
218
249
|
- lib/standard_api/test_case/update_tests.rb
|
219
250
|
- lib/standard_api/views/application/_record.json.jbuilder
|
220
251
|
- lib/standard_api/views/application/index.json.jbuilder
|
252
|
+
- lib/standard_api/views/application/new.json.jbuilder
|
221
253
|
- lib/standard_api/views/application/schema.json.jbuilder
|
222
254
|
- lib/standard_api/views/application/show.json.jbuilder
|
223
255
|
homepage: https://github.com/waratuman/standardapi
|
@@ -237,12 +269,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
237
269
|
version: '0'
|
238
270
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
239
271
|
requirements:
|
240
|
-
- - "
|
272
|
+
- - ">"
|
241
273
|
- !ruby/object:Gem::Version
|
242
|
-
version:
|
274
|
+
version: 1.3.1
|
243
275
|
requirements: []
|
244
276
|
rubyforge_project:
|
245
|
-
rubygems_version: 2.
|
277
|
+
rubygems_version: 2.5.1
|
246
278
|
signing_key:
|
247
279
|
specification_version: 4
|
248
280
|
summary: StandardAPI makes it easy to expose a query interface for your Rails models
|