bullet_train-api 1.2.22 → 1.2.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/api/open_api_controller.rb +1 -124
- data/app/helpers/api/open_api_helper.rb +124 -0
- data/app/views/api/v1/open_api/shared/_paths.yaml.erb +17 -5
- data/app/views/api/v1/open_api/teams/_paths.yaml.erb +12 -3
- data/app/views/api/v1/open_api/users/_paths.yaml.erb +11 -3
- data/lib/bullet_train/api/example_bot.rb +146 -0
- data/lib/bullet_train/api/version.rb +1 -1
- data/lib/bullet_train/api.rb +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52964332e89aebd4034e1a1d6da5f4e96065920023b79a002360787140845d2c
|
4
|
+
data.tar.gz: 969c41617e73866c1fca4658846bc95a425dfb86e608f9f1687dc295a24248b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39313d6d4963ec35c2b606d5bd967b1f04668dfc47de6269271b80450b9e5c5de872f93fa0b4bc8f194fe3ebc25a5507b523d2bf512a09401c8f1bb62b131c95
|
7
|
+
data.tar.gz: 19b9778baedbea755ab32b48b192b7141408a9b4467447a49631d9b5ab550651da37cb31628c4792882c44e059e790db4d42e621d0f4fcb61b8e9b7e38de56ee
|
@@ -1,128 +1,5 @@
|
|
1
|
-
module OpenApiHelper
|
2
|
-
def indent(string, count)
|
3
|
-
lines = string.lines
|
4
|
-
first_line = lines.shift
|
5
|
-
lines = lines.map { |line| (" " * count).to_s + line }
|
6
|
-
lines.unshift(first_line).join.html_safe
|
7
|
-
end
|
8
|
-
|
9
|
-
# TODO: Remove this method? It's not being used anywhere
|
10
|
-
def components_for(model)
|
11
|
-
for_model model do
|
12
|
-
indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/components"), 2)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def current_model
|
17
|
-
@model_stack.last
|
18
|
-
end
|
19
|
-
|
20
|
-
def for_model(model)
|
21
|
-
@model_stack ||= []
|
22
|
-
@model_stack << model
|
23
|
-
result = yield
|
24
|
-
@model_stack.pop
|
25
|
-
result
|
26
|
-
end
|
27
|
-
|
28
|
-
def gem_paths
|
29
|
-
@gem_paths ||= `bundle show --paths`.lines.map { |gem_path| gem_path.chomp }
|
30
|
-
end
|
31
|
-
|
32
|
-
def automatic_paths_for(model, parent, except: [])
|
33
|
-
output = render("api/#{@version}/open_api/shared/paths", except: except)
|
34
|
-
output = Scaffolding::Transformer.new(model.name, [parent&.name]).transform_string(output).html_safe
|
35
|
-
indent(output, 1)
|
36
|
-
end
|
37
|
-
|
38
|
-
def automatic_components_for(model, locals: {})
|
39
|
-
path = "app/views/api/#{@version}"
|
40
|
-
paths = ([path] + gem_paths.map { |gem_path| "#{gem_path}/#{path}" })
|
41
|
-
jbuilder = Jbuilder::Schema.renderer(paths, locals: {
|
42
|
-
# If we ever get to the point where we need a real model here, we should implement an example team in seeds that we can source it from.
|
43
|
-
model.name.underscore.split("/").last.to_sym => model.new,
|
44
|
-
# Same here, if we ever need this to be a real object, this should be `test@example.com` with an `SecureRandom.hex` password.
|
45
|
-
:current_user => User.new
|
46
|
-
}.merge(locals))
|
47
|
-
|
48
|
-
schema_json = jbuilder.json(
|
49
|
-
model.new,
|
50
|
-
title: I18n.t("#{model.name.underscore.pluralize}.label"),
|
51
|
-
# TODO Improve this. We don't have a generic description for models we can use here.
|
52
|
-
description: I18n.t("#{model.name.underscore.pluralize}.label"),
|
53
|
-
)
|
54
|
-
|
55
|
-
attributes_output = JSON.parse(schema_json)
|
56
|
-
|
57
|
-
# Rails attachments aren't technically attributes in a model,
|
58
|
-
# so we add the attributes manually to make them available in the API.
|
59
|
-
if model.attachment_reflections.any?
|
60
|
-
model.attachment_reflections.each do |reflection|
|
61
|
-
attribute_name = reflection.first
|
62
|
-
|
63
|
-
attributes_output["properties"][attribute_name] = {
|
64
|
-
"type" => "object",
|
65
|
-
"description" => attribute_name.titleize.to_s
|
66
|
-
}
|
67
|
-
|
68
|
-
attributes_output["example"].merge!({attribute_name.to_s => nil})
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
if has_strong_parameters?("Api::#{@version.upcase}::#{model.name.pluralize}Controller".constantize)
|
73
|
-
strong_params_module = "Api::#{@version.upcase}::#{model.name.pluralize}Controller::StrongParameters".constantize
|
74
|
-
strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(model, strong_params_module).report
|
75
|
-
if strong_parameter_keys.last.is_a?(Hash)
|
76
|
-
strong_parameter_keys += strong_parameter_keys.pop.keys
|
77
|
-
end
|
78
|
-
|
79
|
-
parameters_output = JSON.parse(schema_json)
|
80
|
-
parameters_output["required"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
|
81
|
-
parameters_output["properties"].select! { |key, value| strong_parameter_keys.include?(key.to_sym) }
|
82
|
-
|
83
|
-
(
|
84
|
-
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3) +
|
85
|
-
indent(" " + parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Parameters:"), 3)
|
86
|
-
).html_safe
|
87
|
-
else
|
88
|
-
|
89
|
-
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3)
|
90
|
-
.html_safe
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def paths_for(model)
|
95
|
-
for_model model do
|
96
|
-
indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/paths"), 1)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def attribute(attribute)
|
101
|
-
heading = t("#{current_model.name.underscore.pluralize}.fields.#{attribute}.heading")
|
102
|
-
attribute_data = current_model.columns_hash[attribute.to_s]
|
103
|
-
|
104
|
-
# Default to `string` when the type returns nil.
|
105
|
-
type = attribute_data.nil? ? "string" : attribute_data.type
|
106
|
-
|
107
|
-
attribute_block = <<~YAML
|
108
|
-
#{attribute}:
|
109
|
-
description: "#{heading}"
|
110
|
-
type: #{type}
|
111
|
-
YAML
|
112
|
-
indent(attribute_block.chomp, 2)
|
113
|
-
end
|
114
|
-
alias_method :parameter, :attribute
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
def has_strong_parameters?(controller)
|
119
|
-
methods = controller.action_methods
|
120
|
-
methods.include?("create") || methods.include?("update")
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
1
|
class Api::OpenApiController < ApplicationController
|
125
|
-
helper
|
2
|
+
helper "api/open_api"
|
126
3
|
|
127
4
|
def set_default_response_format
|
128
5
|
request.format = :yaml
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Api
|
2
|
+
module OpenApiHelper
|
3
|
+
def indent(string, count)
|
4
|
+
lines = string.lines
|
5
|
+
first_line = lines.shift
|
6
|
+
lines = lines.map { |line| (" " * count).to_s + line }
|
7
|
+
lines.unshift(first_line).join.html_safe
|
8
|
+
end
|
9
|
+
|
10
|
+
# TODO: Remove this method? It's not being used anywhere
|
11
|
+
def components_for(model)
|
12
|
+
for_model model do
|
13
|
+
indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/components"), 2)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_model
|
18
|
+
@model_stack.last
|
19
|
+
end
|
20
|
+
|
21
|
+
def for_model(model)
|
22
|
+
@model_stack ||= []
|
23
|
+
@model_stack << model
|
24
|
+
result = yield
|
25
|
+
@model_stack.pop
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def gem_paths
|
30
|
+
@gem_paths ||= `bundle show --paths`.lines.map { |gem_path| gem_path.chomp }
|
31
|
+
end
|
32
|
+
|
33
|
+
def automatic_paths_for(model, parent, except: [])
|
34
|
+
output = render("api/#{@version}/open_api/shared/paths", except: except)
|
35
|
+
output = Scaffolding::Transformer.new(model.name, [parent&.name]).transform_string(output).html_safe
|
36
|
+
indent(output, 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def automatic_components_for(model, locals: {})
|
40
|
+
path = "app/views/api/#{@version}"
|
41
|
+
paths = ([path] + gem_paths.map { |gem_path| "#{gem_path}/#{path}" })
|
42
|
+
jbuilder = Jbuilder::Schema.renderer(paths, locals: {
|
43
|
+
# If we ever get to the point where we need a real model here, we should implement an example team in seeds that we can source it from.
|
44
|
+
model.name.underscore.split("/").last.to_sym => model.new,
|
45
|
+
# Same here, if we ever need this to be a real object, this should be `test@example.com` with an `SecureRandom.hex` password.
|
46
|
+
:current_user => User.new
|
47
|
+
}.merge(locals))
|
48
|
+
|
49
|
+
schema_json = jbuilder.json(
|
50
|
+
model.new,
|
51
|
+
title: I18n.t("#{model.name.underscore.pluralize}.label"),
|
52
|
+
# TODO Improve this. We don't have a generic description for models we can use here.
|
53
|
+
description: I18n.t("#{model.name.underscore.pluralize}.label"),
|
54
|
+
)
|
55
|
+
|
56
|
+
attributes_output = JSON.parse(schema_json)
|
57
|
+
|
58
|
+
# Rails attachments aren't technically attributes in a model,
|
59
|
+
# so we add the attributes manually to make them available in the API.
|
60
|
+
if model.attachment_reflections.any?
|
61
|
+
model.attachment_reflections.each do |reflection|
|
62
|
+
attribute_name = reflection.first
|
63
|
+
|
64
|
+
attributes_output["properties"][attribute_name] = {
|
65
|
+
"type" => "object",
|
66
|
+
"description" => attribute_name.titleize.to_s
|
67
|
+
}
|
68
|
+
|
69
|
+
attributes_output["example"].merge!({attribute_name.to_s => nil})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if has_strong_parameters?("Api::#{@version.upcase}::#{model.name.pluralize}Controller".constantize)
|
74
|
+
strong_params_module = "Api::#{@version.upcase}::#{model.name.pluralize}Controller::StrongParameters".constantize
|
75
|
+
strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(model, strong_params_module).report
|
76
|
+
if strong_parameter_keys.last.is_a?(Hash)
|
77
|
+
strong_parameter_keys += strong_parameter_keys.pop.keys
|
78
|
+
end
|
79
|
+
|
80
|
+
parameters_output = JSON.parse(schema_json)
|
81
|
+
parameters_output["required"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
|
82
|
+
parameters_output["properties"].select! { |key, value| strong_parameter_keys.include?(key.to_sym) }
|
83
|
+
|
84
|
+
(
|
85
|
+
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3) +
|
86
|
+
indent(" " + parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Parameters:"), 3)
|
87
|
+
).html_safe
|
88
|
+
else
|
89
|
+
|
90
|
+
indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3)
|
91
|
+
.html_safe
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def paths_for(model)
|
96
|
+
for_model model do
|
97
|
+
indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/paths"), 1)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def attribute(attribute)
|
102
|
+
heading = t("#{current_model.name.underscore.pluralize}.fields.#{attribute}.heading")
|
103
|
+
attribute_data = current_model.columns_hash[attribute.to_s]
|
104
|
+
|
105
|
+
# Default to `string` when the type returns nil.
|
106
|
+
type = attribute_data.nil? ? "string" : attribute_data.type
|
107
|
+
|
108
|
+
attribute_block = <<~YAML
|
109
|
+
#{attribute}:
|
110
|
+
description: "#{heading}"
|
111
|
+
type: #{type}
|
112
|
+
YAML
|
113
|
+
indent(attribute_block.chomp, 2)
|
114
|
+
end
|
115
|
+
alias_method :parameter, :attribute
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def has_strong_parameters?(controller)
|
120
|
+
methods = controller.action_methods
|
121
|
+
methods.include?("create") || methods.include?("update")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<% unless except.include?(:index) %>
|
5
5
|
get:
|
6
6
|
tags:
|
7
|
-
-
|
7
|
+
- Scaffolding::CompletelyConcrete::TangibleThing
|
8
8
|
summary: "List Tangible Things"
|
9
9
|
operationId: listScaffoldingCompletelyConcreteTangibleThings
|
10
10
|
parameters:
|
@@ -30,11 +30,13 @@
|
|
30
30
|
type: array
|
31
31
|
items:
|
32
32
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
33
|
+
example:
|
34
|
+
<%= FactoryBot.get_example(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
33
35
|
<% end %>
|
34
36
|
<% unless except.include?(:create) %>
|
35
37
|
post:
|
36
38
|
tags:
|
37
|
-
-
|
39
|
+
- Scaffolding::CompletelyConcrete::TangibleThing
|
38
40
|
summary: "Create Tangible Thing"
|
39
41
|
operationId: createScaffoldingCompletelyConcreteTangibleThings
|
40
42
|
parameters:
|
@@ -54,6 +56,8 @@
|
|
54
56
|
scaffolding_completely_concrete_tangible_thing:
|
55
57
|
type: object
|
56
58
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
|
59
|
+
example:
|
60
|
+
<%= FactoryBot.post_parameters(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
57
61
|
responses:
|
58
62
|
"404":
|
59
63
|
description: "Not Found"
|
@@ -63,6 +67,8 @@
|
|
63
67
|
application/json:
|
64
68
|
schema:
|
65
69
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
70
|
+
example:
|
71
|
+
<%= FactoryBot.post_examples(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
66
72
|
<% end %>
|
67
73
|
<% end %>
|
68
74
|
<% unless except.include?(:show) && except.include?(:update) && except.include?(:destroy) %>
|
@@ -70,7 +76,7 @@
|
|
70
76
|
<% unless except.include?(:show) %>
|
71
77
|
get:
|
72
78
|
tags:
|
73
|
-
-
|
79
|
+
- Scaffolding::CompletelyConcrete::TangibleThing
|
74
80
|
summary: "Fetch Tangible Thing"
|
75
81
|
operationId: getScaffoldingCompletelyConcreteTangibleThings
|
76
82
|
parameters:
|
@@ -84,11 +90,13 @@
|
|
84
90
|
application/json:
|
85
91
|
schema:
|
86
92
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
93
|
+
example:
|
94
|
+
<%= FactoryBot.get_example(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
87
95
|
<% end %>
|
88
96
|
<% unless except.include?(:update) %>
|
89
97
|
put:
|
90
98
|
tags:
|
91
|
-
-
|
99
|
+
- Scaffolding::CompletelyConcrete::TangibleThing
|
92
100
|
summary: "Update Tangible Thing"
|
93
101
|
operationId: updateScaffoldingCompletelyConcreteTangibleThings
|
94
102
|
parameters:
|
@@ -104,6 +112,8 @@
|
|
104
112
|
scaffolding_completely_concrete_tangible_thing:
|
105
113
|
type: object
|
106
114
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
|
115
|
+
example:
|
116
|
+
<%= FactoryBot.put_parameters(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
107
117
|
responses:
|
108
118
|
"404":
|
109
119
|
description: "Not Found"
|
@@ -113,11 +123,13 @@
|
|
113
123
|
application/json:
|
114
124
|
schema:
|
115
125
|
$ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingAttributes"
|
126
|
+
example:
|
127
|
+
<%= FactoryBot.put_example(:scaffolding_completely_concrete_tangible_thing, version: @version) %>
|
116
128
|
<% end %>
|
117
129
|
<% unless except.include?(:destroy) %>
|
118
130
|
delete:
|
119
131
|
tags:
|
120
|
-
-
|
132
|
+
- Scaffolding::CompletelyConcrete::TangibleThing
|
121
133
|
summary: "Remove Tangible Thing"
|
122
134
|
operationId: removeScaffoldingCompletelyConcreteTangibleThings
|
123
135
|
parameters:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/teams:
|
2
2
|
get:
|
3
3
|
tags:
|
4
|
-
-
|
4
|
+
- Team
|
5
5
|
summary: "List Teams"
|
6
6
|
operationId: listTeams
|
7
7
|
parameters:
|
@@ -22,10 +22,13 @@
|
|
22
22
|
type: array
|
23
23
|
items:
|
24
24
|
$ref: "#/components/schemas/TeamAttributes"
|
25
|
+
example:
|
26
|
+
<%= FactoryBot.get_examples(:team, version: @version) %>
|
27
|
+
|
25
28
|
/teams/{id}:
|
26
29
|
get:
|
27
30
|
tags:
|
28
|
-
-
|
31
|
+
- Team
|
29
32
|
summary: "Fetch Team"
|
30
33
|
operationId: fetchTeam
|
31
34
|
parameters:
|
@@ -39,9 +42,11 @@
|
|
39
42
|
application/json:
|
40
43
|
schema:
|
41
44
|
$ref: "#/components/schemas/TeamAttributes"
|
45
|
+
example:
|
46
|
+
<%= FactoryBot.get_example(:team, version: @version) %>
|
42
47
|
put:
|
43
48
|
tags:
|
44
|
-
-
|
49
|
+
- Team
|
45
50
|
summary: "Update Team"
|
46
51
|
operationId: updateTeam
|
47
52
|
parameters:
|
@@ -57,6 +62,8 @@
|
|
57
62
|
team:
|
58
63
|
type: object
|
59
64
|
$ref: "#/components/schemas/TeamParameters"
|
65
|
+
example:
|
66
|
+
<%= FactoryBot.put_parameters(:team, version: @version) %>
|
60
67
|
responses:
|
61
68
|
"404":
|
62
69
|
description: "Not Found"
|
@@ -66,3 +73,5 @@
|
|
66
73
|
application/json:
|
67
74
|
schema:
|
68
75
|
$ref: "#/components/schemas/TeamAttributes"
|
76
|
+
example:
|
77
|
+
<%= FactoryBot.put_example(:team, version: @version) %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/users:
|
2
2
|
get:
|
3
3
|
tags:
|
4
|
-
-
|
4
|
+
- User
|
5
5
|
summary: "List Users"
|
6
6
|
operationId: listUsers
|
7
7
|
parameters:
|
@@ -22,10 +22,12 @@
|
|
22
22
|
type: array
|
23
23
|
items:
|
24
24
|
$ref: "#/components/schemas/UserAttributes"
|
25
|
+
example:
|
26
|
+
<%= FactoryBot.get_examples(:user, version: @version) %>
|
25
27
|
/users/{id}:
|
26
28
|
get:
|
27
29
|
tags:
|
28
|
-
-
|
30
|
+
- User
|
29
31
|
summary: "Fetch User"
|
30
32
|
operationId: fetchUser
|
31
33
|
parameters:
|
@@ -39,9 +41,11 @@
|
|
39
41
|
application/json:
|
40
42
|
schema:
|
41
43
|
$ref: "#/components/schemas/UserAttributes"
|
44
|
+
example:
|
45
|
+
<%= FactoryBot.get_example(:user, version: @version) %>
|
42
46
|
put:
|
43
47
|
tags:
|
44
|
-
-
|
48
|
+
- User
|
45
49
|
summary: "Update User"
|
46
50
|
operationId: updateUser
|
47
51
|
parameters:
|
@@ -57,6 +61,8 @@
|
|
57
61
|
user:
|
58
62
|
type: object
|
59
63
|
$ref: "#/components/schemas/UserParameters"
|
64
|
+
example:
|
65
|
+
<%= FactoryBot.put_parameters(:user, version: @version) %>
|
60
66
|
responses:
|
61
67
|
"404":
|
62
68
|
description: "Not Found"
|
@@ -66,3 +72,5 @@
|
|
66
72
|
application/json:
|
67
73
|
schema:
|
68
74
|
$ref: "#/components/schemas/UserAttributes"
|
75
|
+
example:
|
76
|
+
<%= FactoryBot.put_example(:user, version: @version) %>
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require_relative "../../../app/helpers/api/open_api_helper"
|
2
|
+
|
3
|
+
module FactoryBot
|
4
|
+
module ExampleBot
|
5
|
+
attr_accessor :tables_to_reset
|
6
|
+
|
7
|
+
def example(model, **options)
|
8
|
+
@tables_to_reset = [model.to_s.pluralize]
|
9
|
+
|
10
|
+
object = nil
|
11
|
+
|
12
|
+
ActiveRecord::Base.transaction do
|
13
|
+
instance = FactoryBot.create(factory(model), **options)
|
14
|
+
object = deep_clone(instance)
|
15
|
+
|
16
|
+
raise ActiveRecord::Rollback
|
17
|
+
end
|
18
|
+
|
19
|
+
reset_tables!
|
20
|
+
object
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_list(model, quantity, **options)
|
24
|
+
@tables_to_reset = [model.to_s.pluralize]
|
25
|
+
|
26
|
+
objects = []
|
27
|
+
|
28
|
+
ActiveRecord::Base.transaction do
|
29
|
+
instances = FactoryBot.create_list(factory(model), quantity, **options)
|
30
|
+
|
31
|
+
instances.each do |instance|
|
32
|
+
objects << deep_clone(instance)
|
33
|
+
end
|
34
|
+
|
35
|
+
raise ActiveRecord::Rollback
|
36
|
+
end
|
37
|
+
|
38
|
+
reset_tables!
|
39
|
+
objects
|
40
|
+
end
|
41
|
+
|
42
|
+
%i[get_examples get_example post_examples post_parameters put_example put_parameters patch_example patch_parameters].each do |method|
|
43
|
+
define_method(method) do |model, **options|
|
44
|
+
_path_examples(method.to_s, model, **options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def factory(model)
|
51
|
+
factories = FactoryBot.factories.instance_variable_get(:@items).keys
|
52
|
+
factories.include?("#{model}_example") ? "#{model}_example" : model
|
53
|
+
end
|
54
|
+
|
55
|
+
def reset_tables!
|
56
|
+
@tables_to_reset.each do |name|
|
57
|
+
ActiveRecord::Base.connection.reset_pk_sequence!(name) if ActiveRecord::Base.connection.table_exists?(name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def deep_clone(instance)
|
62
|
+
clone = instance.clone
|
63
|
+
|
64
|
+
instance.class.reflections.each do |name, reflection|
|
65
|
+
if reflection.macro == :has_many
|
66
|
+
associations = instance.send(name).map { |association| association.clone }
|
67
|
+
clone.send("#{name}=", associations)
|
68
|
+
@tables_to_reset << name
|
69
|
+
elsif %i[belongs_to has_one].include?(reflection.macro)
|
70
|
+
clone.send("#{name}=", instance.send(name).clone)
|
71
|
+
@tables_to_reset << name.pluralize
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
clone
|
76
|
+
end
|
77
|
+
|
78
|
+
include ::Api::OpenApiHelper
|
79
|
+
def _path_examples(method, model, **options)
|
80
|
+
version = options.delete(:version) || "v1"
|
81
|
+
|
82
|
+
case method.split("_").first
|
83
|
+
when "get"
|
84
|
+
count = (options.delete(:count) || method == "get_examples") ? 2 : 1
|
85
|
+
template, class_name, var_name, values = _set_values(method, model, count)
|
86
|
+
else
|
87
|
+
template, class_name, var_name, values = _set_values("get_example", model)
|
88
|
+
|
89
|
+
unless %w[example examples].include?(method.split("_").last)
|
90
|
+
if has_strong_parameters?("::Api::#{version.upcase}::#{class_name.pluralize}Controller".constantize)
|
91
|
+
strong_params_module = "::Api::#{version.upcase}::#{class_name.pluralize}Controller::StrongParameters".constantize
|
92
|
+
strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(class_name.constantize, strong_params_module).report
|
93
|
+
if strong_parameter_keys.last.is_a?(Hash)
|
94
|
+
strong_parameter_keys += strong_parameter_keys.pop.keys
|
95
|
+
end
|
96
|
+
|
97
|
+
output = _json_output(template, version, class_name, var_name, values)
|
98
|
+
|
99
|
+
parameters_output = JSON.parse(output)
|
100
|
+
parameters_output&.select! { |key| strong_parameter_keys.include?(key.to_sym) }
|
101
|
+
|
102
|
+
return indent(parameters_output.to_yaml.delete_prefix("---\n"), 6).html_safe
|
103
|
+
end
|
104
|
+
return nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
_yaml_output(template, version, class_name, var_name, values)
|
109
|
+
end
|
110
|
+
|
111
|
+
def _set_values(method, model, count = 1)
|
112
|
+
if count > 1
|
113
|
+
values = FactoryBot.example_list(model, count)
|
114
|
+
class_name = values.first.class.name
|
115
|
+
var_name = class_name.demodulize.underscore.pluralize
|
116
|
+
else
|
117
|
+
values = FactoryBot.example(model)
|
118
|
+
class_name = values.class.name
|
119
|
+
var_name = class_name.demodulize.underscore
|
120
|
+
end
|
121
|
+
|
122
|
+
template = (method == "get_examples") ? "index" : "show"
|
123
|
+
|
124
|
+
[template, class_name, var_name, values]
|
125
|
+
end
|
126
|
+
|
127
|
+
def _json_output(template, version, class_name, var_name, values)
|
128
|
+
ActionController::Base.render(
|
129
|
+
template: "api/#{version}/#{class_name.underscore.pluralize}/#{template}",
|
130
|
+
assigns: {"#{var_name}": values},
|
131
|
+
formats: :json
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def _yaml_output(template, version, class_name, var_name, values)
|
136
|
+
indent(
|
137
|
+
JSON.parse(
|
138
|
+
_json_output(template, version, class_name, var_name, values)
|
139
|
+
).to_yaml
|
140
|
+
.delete_prefix("---\n"), 7
|
141
|
+
).html_safe
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
extend ExampleBot
|
146
|
+
end
|
data/lib/bullet_train/api.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 2.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: factory_bot
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: bullet_train
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,6 +155,7 @@ files:
|
|
141
155
|
- app/controllers/concerns/api/controllers/base.rb
|
142
156
|
- app/controllers/concerns/api/v1/teams/controller_base.rb
|
143
157
|
- app/controllers/concerns/api/v1/users/controller_base.rb
|
158
|
+
- app/helpers/api/open_api_helper.rb
|
144
159
|
- app/models/platform/access_token.rb
|
145
160
|
- app/models/platform/application.rb
|
146
161
|
- app/views/account/platform/access_tokens/_breadcrumbs.html.erb
|
@@ -188,6 +203,7 @@ files:
|
|
188
203
|
- config/routes.rb
|
189
204
|
- lib/bullet_train/api.rb
|
190
205
|
- lib/bullet_train/api/engine.rb
|
206
|
+
- lib/bullet_train/api/example_bot.rb
|
191
207
|
- lib/bullet_train/api/strong_parameters_reporter.rb
|
192
208
|
- lib/bullet_train/api/version.rb
|
193
209
|
- lib/bullet_train/platform.rb
|