bullet_train-api 1.2.22 → 1.2.23
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/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
|