rest-api-generator 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +191 -43
  4. data/README.md +173 -7
  5. data/Rakefile +1 -1
  6. data/lib/generators/rest_api_generator/helpers.rb +72 -0
  7. data/lib/generators/rest_api_generator/resource_generator.rb +33 -16
  8. data/lib/generators/rest_api_generator/spec/rspec_generator.rb +36 -0
  9. data/lib/generators/rest_api_generator/spec/rswag_generator.rb +54 -0
  10. data/lib/generators/rest_api_generator/spec/templates/rspec/nested_resource_controller_spec.rb.tt +62 -0
  11. data/lib/generators/rest_api_generator/{templates/rest_api_spec.rb.tt → spec/templates/rspec/resource_controller_spec.rb.tt} +5 -5
  12. data/lib/generators/rest_api_generator/spec/templates/rswag/nested_resource_controller_spec.rb.tt +116 -0
  13. data/lib/generators/rest_api_generator/spec/templates/rswag/resource_controller_spec.rb.tt +111 -0
  14. data/lib/generators/rest_api_generator/templates/child_api_controller.rb.tt +10 -9
  15. data/lib/generators/rest_api_generator/templates/implicit_child_resource_controller.rb.tt +4 -0
  16. data/lib/generators/rest_api_generator/templates/implicit_resource_controller.rb.tt +4 -0
  17. data/lib/generators/rest_api_generator/templates/rest_api_controller.rb.tt +2 -0
  18. data/lib/rest-api-generator.rb +3 -0
  19. data/lib/rest_api_generator/application_controller.rb +8 -0
  20. data/lib/rest_api_generator/child_resource_controller.rb +97 -0
  21. data/lib/rest_api_generator/filterable.rb +30 -0
  22. data/lib/rest_api_generator/helpers/render.rb +1 -1
  23. data/lib/rest_api_generator/orderable.rb +30 -0
  24. data/lib/rest_api_generator/resource_controller.rb +73 -0
  25. data/lib/rest_api_generator/version.rb +1 -1
  26. data/lib/rest_api_generator.rb +11 -1
  27. data/rest-api-generator.gemspec +11 -4
  28. metadata +90 -8
  29. data/lib/generators/rest_api_generator/templates/child_api_spec.rb.tt +0 -59
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators"
4
+ require "rails/generators/active_model"
5
+ require "rails/generators/rails/model/model_generator"
4
6
  require "generators/rest_api_generator/helpers"
5
7
  module RestApiGenerator
6
8
  class ResourceGenerator < Rails::Generators::NamedBase
@@ -8,31 +10,46 @@ module RestApiGenerator
8
10
  source_root File.expand_path("templates", __dir__)
9
11
 
10
12
  argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
13
+ class_option :eject, type: :boolean, default: false
11
14
  class_option :scope, type: :string, default: ""
12
-
13
- API_CONTROLLER_DIR_PATH = "app/controllers"
14
- API_TEST_DIR_PATH = "spec/requests"
15
+ class_option :father, type: :string, default: ""
16
+ hook_for :spec, in: "rest_api_generator:spec", default: "rspec"
15
17
 
16
18
  def create_service_file
17
- Rails::Generators.invoke("model", [file_name, build_model_attributes])
18
- if options["scope"].empty?
19
- controller_path = "#{API_CONTROLLER_DIR_PATH}/#{file_name.pluralize}_controller.rb"
20
- controller_test_path = "#{API_TEST_DIR_PATH}/#{file_name.pluralize}_controller_spec.rb"
21
- template "rest_api_controller.rb", controller_path
22
- template "rest_api_spec.rb", controller_test_path
23
- routes_string = "resources :#{file_name.pluralize}"
24
- route routes_string
19
+ create_model_files
20
+
21
+ template controller_template, controller_path
22
+
23
+ # Routes
24
+ if options["scope"].blank? && options["father"].blank?
25
+ route "resources :#{file_name.pluralize}"
25
26
  else
26
- scope_path = options["scope"].pluralize
27
- controller_path = "#{API_CONTROLLER_DIR_PATH}/#{scope_path}/#{file_name.pluralize}_controller.rb"
28
- controller_test_path = "#{API_TEST_DIR_PATH}/#{scope_path}/#{file_name.pluralize}_controller_spec.rb"
29
- template "child_api_controller.rb", controller_path
30
- template "child_api_spec.rb", controller_test_path
27
+ log("You need to manually setup routes files for nested or scoped resource")
31
28
  end
32
29
  end
33
30
 
34
31
  private
35
32
 
33
+ def controller_template
34
+ if options["eject"]
35
+ if options["father"].present?
36
+ "child_api_controller.rb"
37
+ else
38
+ "rest_api_controller.rb"
39
+ end
40
+ elsif options["father"].present?
41
+ "implicit_child_resource_controller.rb"
42
+ else
43
+ "implicit_resource_controller.rb"
44
+ end
45
+ end
46
+
47
+ def create_model_files
48
+ g = Rails::Generators::ModelGenerator.new([file_name, build_model_attributes])
49
+ g.destination_root = destination_root
50
+ g.invoke_all
51
+ end
52
+
36
53
  def build_model_attributes
37
54
  model_attributes = []
38
55
  attributes.each do |attribute|
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "generators/rest_api_generator/helpers"
5
+
6
+ module RestApiGenerator
7
+ module Spec
8
+ class RspecGenerator < Rails::Generators::NamedBase
9
+ include Helpers
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
13
+ class_option :eject, type: :boolean, default: false
14
+ class_option :scope, type: :string, default: ""
15
+ class_option :father, type: :string, default: ""
16
+
17
+ def create_service_file
18
+ template spec_controller_template, controller_test_path
19
+ end
20
+
21
+ private
22
+
23
+ def controller_test_path
24
+ "#{API_TEST_DIR_PATH}#{scope_path}/#{file_name.pluralize}_controller_spec.rb"
25
+ end
26
+
27
+ def spec_controller_template
28
+ if options["father"].present?
29
+ "rspec/resource_controller_spec.rb"
30
+ else
31
+ "rspec/nested_resource_controller_spec.rb"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "generators/rest_api_generator/helpers"
5
+
6
+ module RestApiGenerator
7
+ module Spec
8
+ class RswagGenerator < Rails::Generators::NamedBase
9
+ include Helpers
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
13
+ class_option :eject, type: :boolean, default: false
14
+ class_option :scope, type: :string, default: ""
15
+ class_option :father, type: :string, default: ""
16
+
17
+ def create_service_file
18
+ template spec_controller_template, controller_test_path
19
+ end
20
+
21
+ private
22
+
23
+ # Changes nested routes for rswag format
24
+ # Example: /cars/{car.id}/drivers/{id}
25
+ def nested_routes
26
+ return "" if options["father"].blank?
27
+
28
+ "#{options["father"].downcase.pluralize}/{#{options["father"].singularize.downcase}_id}/#{plural_name}"
29
+ end
30
+
31
+ def spec_routes
32
+ {
33
+ index: initial_route,
34
+ show: initial_route + "/{id}",
35
+ create: initial_route,
36
+ update: initial_route + "/{id}",
37
+ delete: initial_route + "/{id}",
38
+ }
39
+ end
40
+
41
+ def controller_test_path
42
+ "#{API_TEST_DIR_PATH}#{scope_path}/#{file_name.pluralize}_spec.rb"
43
+ end
44
+
45
+ def spec_controller_template
46
+ if options["father"].present?
47
+ "rswag/nested_resource_controller_spec.rb"
48
+ else
49
+ "rswag/resource_controller_spec.rb"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,62 @@
1
+ require "rails_helper"
2
+
3
+ RSpec.describe "<%= class_name %>", type: :request do
4
+ let(:valid_attributes) { attributes_for(:<%= singular_table_name %>) }
5
+
6
+ describe "GET /<%= plural_name %>" do
7
+ let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
8
+ let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options['father'].downcase %>: <%= options['father'].downcase %>) }
9
+
10
+ it "renders a successful response" do
11
+ get "<%= spec_routes[:index] %>"
12
+ expect(response).to be_successful
13
+ end
14
+ end
15
+
16
+
17
+ describe "GET /<%= singular_name %>" do
18
+ let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
19
+ let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options['father'].downcase.singularize %>: <%= options['father'].downcase %>)}
20
+
21
+ it "gets an <%= singular_name %>" do
22
+ get "<%= spec_routes[:show] %>"
23
+ expect(response).to be_successful
24
+ end
25
+ end
26
+
27
+
28
+ describe "POST /<%= plural_name %>" do
29
+ context "with valid parameters" do
30
+ let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
31
+ it "creates a new <%= singular_name %>" do
32
+ expect do
33
+ post "<%= spec_routes[:create] %>",
34
+ params: { <%= singular_name %>: valid_attributes }
35
+ end.to change(<%= class_name %>, :count).by(1)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "PATCH /<%= plural_name %>" do
41
+ let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
42
+ let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options['father'].downcase.singularize %>: <%= options['father'].downcase.singularize %>)}
43
+
44
+ it "updates an <%= singular_name %>" do
45
+ patch "<%= spec_routes[:update] %>",
46
+ params: { <%= singular_name %>: valid_attributes }
47
+ expect(response).to have_http_status(:success)
48
+ end
49
+ end
50
+
51
+ describe "DELETE /<%= singular_name %>" do
52
+ let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
53
+
54
+ it "deletes an <%= singular_name %>" do
55
+ <%= singular_table_name %> = create(:<%=singular_table_name %>, <%= options['father'].downcase.singularize %>: <%= options['father'].downcase.singularize %>)
56
+ expect do
57
+ delete "<%= spec_routes[:delete] %>"
58
+ end.to change(<%= class_name %>, :count).by(-1)
59
+ end
60
+ end
61
+
62
+ end
@@ -7,14 +7,14 @@ RSpec.describe "<%= class_name %>", type: :request do
7
7
  describe "GET /<%= plural_name %>" do
8
8
  it "returns http success" do
9
9
  create(:<%= singular_table_name %>)
10
- get "/<%= plural_name %>"
10
+ get "<%= spec_routes[:index] %>"
11
11
  expect(response).to have_http_status(:success)
12
12
  end
13
13
  end
14
14
 
15
15
  describe "GET /<%= plural_name %>/:id" do
16
16
  it "returns http success" do
17
- get "/<%= plural_name %>/#{<%= singular_name %>.id}"
17
+ get "<%= spec_routes[:show] %>"
18
18
  expect(response).to have_http_status(:success)
19
19
  end
20
20
  end
@@ -22,7 +22,7 @@ RSpec.describe "<%= class_name %>", type: :request do
22
22
  describe "POST /<%= plural_name %>" do
23
23
  it "creates a new item" do
24
24
  expect do
25
- post "/<%= plural_name %>",
25
+ post "<%= spec_routes[:create] %>",
26
26
  params: { <%= singular_name %>: valid_attributes }
27
27
  end.to change(<%= class_name %>, :count).by(1)
28
28
  end
@@ -30,7 +30,7 @@ RSpec.describe "<%= class_name %>", type: :request do
30
30
 
31
31
  describe "PATCH /<%= plural_name %>/:id" do
32
32
  it "return http success" do
33
- patch "/<%= plural_name %>/#{<%= singular_name %>.id}",
33
+ patch "<%= spec_routes[:update] %>",
34
34
  params: { <%= singular_name %>: valid_attributes }
35
35
  expect(response).to have_http_status(:success)
36
36
  end
@@ -40,7 +40,7 @@ RSpec.describe "<%= class_name %>", type: :request do
40
40
  it "deletes an <%= plural_name %>" do
41
41
  item = create(:<%= singular_name %>)
42
42
  expect do
43
- delete "/<%= plural_name %>/#{item.id}"
43
+ delete "<%= spec_routes[:delete] %>"
44
44
  end.to change(<%= class_name %>, :count).by(-1)
45
45
  end
46
46
  end
@@ -0,0 +1,116 @@
1
+ require "rails_helper"
2
+
3
+ RSpec.describe "<%= spec_routes[:index] %>", type: :request do
4
+ let(:resource) { create(:<%= singular_table_name %>, <%= options['father'].downcase.singularize %>: parent_resource) }
5
+ let(:parent_resource ) { create(:<%= options['father'].downcase.singularize %>) }
6
+
7
+ path "<%= spec_routes[:index] %>" do
8
+ parameter name: "<%= options['father'].downcase.singularize %>_id", in: :path, type: :string, description: "<%= options['father'].downcase.singularize %> id"
9
+ let(:<%= options['father'].downcase.singularize %>_id) { parent_resource.id }
10
+
11
+ get("list <%= plural_name %>") do
12
+ consumes "application/json"
13
+
14
+ response(200, "successful") do
15
+ after do |example|
16
+ example.metadata[:response][:content] = {
17
+ "application/json" => {
18
+ example: JSON.parse(response.body, symbolize_names: true)
19
+ }
20
+ }
21
+ end
22
+
23
+ run_test!
24
+ end
25
+ end
26
+
27
+ post("create <%= singular_table_name %>") do
28
+ consumes "application/json"
29
+
30
+ # You'll want to customize the parameter types...
31
+ parameter name: :<%= singular_table_name %>, in: :body, schema: {
32
+ type: :object,
33
+ properties: {
34
+ <% attributes.each do |attribute| -%>
35
+ <%= attribute.name %>: { type: :string },
36
+ <% end -%>
37
+ }
38
+ }
39
+ response(201, "successful") do
40
+ let(:<%= singular_table_name %>) { attributes_for(:<%= singular_table_name %>) }
41
+
42
+ after do |example|
43
+ example.metadata[:response][:content] = {
44
+ "application/json" => {
45
+ example: JSON.parse(response.body, symbolize_names: true)
46
+ }
47
+ }
48
+ end
49
+
50
+ run_test!
51
+ end
52
+ end
53
+ end
54
+
55
+ path "<%= spec_routes[:show] %>" do
56
+ parameter name: "id", in: :path, type: :string, description: "id"
57
+ parameter name: "<%= options['father'].downcase.singularize %>_id", in: :path, type: :string, description: "<%= options['father'].downcase.singularize %> id"
58
+
59
+ let(:id) { resource.id }
60
+ let(:<%= options['father'].downcase.singularize %>_id) { parent_resource.id }
61
+
62
+ get("show <%= singular_table_name %>") do
63
+ consumes "application/json"
64
+
65
+ response(200, "successful") do
66
+
67
+ after do |example|
68
+ example.metadata[:response][:content] = {
69
+ "application/json" => {
70
+ example: JSON.parse(response.body, symbolize_names: true)
71
+ }
72
+ }
73
+ end
74
+ run_test!
75
+ end
76
+ end
77
+
78
+
79
+ patch("update <%= singular_table_name %>") do
80
+ consumes "application/json"
81
+
82
+ # You'll want to customize the parameter types...
83
+ parameter name: :<%= singular_table_name %>, in: :body, schema: {
84
+ type: :object,
85
+ properties: {
86
+ <% attributes.each do |attribute| -%>
87
+ <%= attribute.name %>: { type: :string },
88
+ <% end -%>
89
+ }
90
+ }
91
+
92
+ response(200, "successful") do
93
+ let(:<%= singular_table_name %>) { attributes_for(:<%= singular_table_name %>) }
94
+
95
+ after do |example|
96
+ example.metadata[:response][:content] = {
97
+ "application/json" => {
98
+ example: JSON.parse(response.body, symbolize_names: true)
99
+ }
100
+ }
101
+ end
102
+
103
+ run_test!
104
+ end
105
+ end
106
+
107
+ delete("delete plan") do
108
+ consumes "application/json"
109
+
110
+ response(204, "successful") do
111
+
112
+ run_test!
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,111 @@
1
+ require "rails_helper"
2
+
3
+ RSpec.describe "<%= spec_routes[:index] %>", type: :request do
4
+ let(:resource) { create(:<%= singular_table_name %>) }
5
+
6
+ path "<%= spec_routes[:index] %>" do
7
+ get("list <%= plural_name %>") do
8
+ consumes "application/json"
9
+
10
+ response(200, "successful") do
11
+ after do |example|
12
+ example.metadata[:response][:content] = {
13
+ "application/json" => {
14
+ example: JSON.parse(response.body, symbolize_names: true)
15
+ }
16
+ }
17
+ end
18
+
19
+ run_test!
20
+ end
21
+ end
22
+
23
+ post("create <%= singular_table_name %>") do
24
+ consumes "application/json"
25
+
26
+ # You'll want to customize the parameter types...
27
+ parameter name: :<%= singular_table_name %>, in: :body, schema: {
28
+ type: :object,
29
+ properties: {
30
+ <% attributes.each do |attribute| -%>
31
+ <%= attribute.name %>: { type: :string },
32
+ <% end -%>
33
+ }
34
+ }
35
+ response(201, "successful") do
36
+ let(:<%= singular_table_name %>) { attributes_for(:<%= singular_table_name %>) }
37
+
38
+ after do |example|
39
+ example.metadata[:response][:content] = {
40
+ "application/json" => {
41
+ example: JSON.parse(response.body, symbolize_names: true)
42
+ }
43
+ }
44
+ end
45
+
46
+ run_test!
47
+ end
48
+ end
49
+ end
50
+
51
+ path "<%= spec_routes[:show] %>" do
52
+ parameter name: "id", in: :path, type: :string, description: "id"
53
+
54
+ get("show <%= singular_table_name %>") do
55
+ consumes "application/json"
56
+
57
+ response(200, "successful") do
58
+ let(:id) { resource.id }
59
+
60
+ after do |example|
61
+ example.metadata[:response][:content] = {
62
+ "application/json" => {
63
+ example: JSON.parse(response.body, symbolize_names: true)
64
+ }
65
+ }
66
+ end
67
+ run_test!
68
+ end
69
+ end
70
+
71
+
72
+ patch("update <%= singular_table_name %>") do
73
+ consumes "application/json"
74
+
75
+ # You'll want to customize the parameter types...
76
+ parameter name: :<%= singular_table_name %>, in: :body, schema: {
77
+ type: :object,
78
+ properties: {
79
+ <% attributes.each do |attribute| -%>
80
+ <%= attribute.name %>: { type: :string },
81
+ <% end -%>
82
+ }
83
+ }
84
+
85
+ response(200, "successful") do
86
+ let(:id) { resource.id }
87
+ let(:<%= singular_table_name %>) { attributes_for(:<%= singular_table_name %>) }
88
+
89
+ after do |example|
90
+ example.metadata[:response][:content] = {
91
+ "application/json" => {
92
+ example: JSON.parse(response.body, symbolize_names: true)
93
+ }
94
+ }
95
+ end
96
+
97
+ run_test!
98
+ end
99
+ end
100
+
101
+ delete("delete plan") do
102
+ consumes "application/json"
103
+
104
+ response(204, "successful") do
105
+ let(:id) { resource.id }
106
+
107
+ run_test!
108
+ end
109
+ end
110
+ end
111
+ end
@@ -1,9 +1,10 @@
1
+ <% scope_namespacing do -%>
1
2
  class <%= class_name.pluralize %>Controller < ApplicationController
2
- before_action :set_<%= options['scope'].downcase %>
3
- before_action :set_<%= singular_name %>, only: %i[show update destroy]
3
+ before_action :set_<%= options['father'].downcase.singularize %>
4
+ before_action :set_<%= singular_name %>, only: %i[ show update destroy ]
4
5
 
5
6
  def index
6
- @<%= plural_name %> = @<%= options['scope'].downcase %>.<%= plural_name %>
7
+ @<%= plural_name %> = @<%= options['father'].downcase.singularize %>.<%= plural_name %>
7
8
  render json: @<%= plural_name %>, status: :ok
8
9
  end
9
10
 
@@ -12,7 +13,7 @@ class <%= class_name.pluralize %>Controller < ApplicationController
12
13
  end
13
14
 
14
15
  def create
15
- @<%= singular_name %> = @<%= options['scope'].downcase %>.<%= plural_name %>.create!(<%= singular_name %>_params)
16
+ @<%= singular_name %> = @<%= options['father'].downcase.singularize %>.<%= plural_name %>.create!(<%= singular_name %>_params)
16
17
  render json: @<%= singular_name %>, status: :created
17
18
  end
18
19
 
@@ -25,18 +26,18 @@ class <%= class_name.pluralize %>Controller < ApplicationController
25
26
  @<%= singular_name %>.destroy!
26
27
  end
27
28
 
28
-
29
29
  private
30
30
 
31
- def set_<%= options['scope'].downcase %>
32
- @<%= options['scope'].downcase %> = <%= options['scope'] %>.find(params[:<%= options['scope'].downcase %>_id])
31
+ def set_<%= options['father'].downcase.singularize %>
32
+ @<%= options['father'].downcase %> = <%= options['father'] %>.find(params[:<%= options['father'].downcase.singularize %>_id])
33
33
  end
34
34
 
35
35
  def set_<%= singular_name %>
36
- @<%= singular_name %> = @<%= options['scope'].downcase %>.<%= plural_name %>.find(params[:id])
36
+ @<%= singular_name %> = @<%= options['father'].downcase.singularize %>.<%= plural_name %>.find(params[:id])
37
37
  end
38
38
 
39
39
  def <%= singular_name %>_params
40
40
  params.require(:<%= singular_name %>).permit(<%= attributes.map { |a| ':' + a.name }.join(', ') %>)
41
41
  end
42
- end
42
+ end
43
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ <% scope_namespacing do -%>
2
+ class <%= class_name.pluralize %>Controller < RestApiGenerator::ChildResourceController
3
+ end
4
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ <% scope_namespacing do -%>
2
+ class <%= class_name.pluralize %>Controller < RestApiGenerator::ResourceController
3
+ end
4
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% scope_namespacing do -%>
1
2
  class <%= class_name.pluralize %>Controller < ApplicationController
2
3
  before_action :set_<%= singular_name %>, only: %i[show update destroy]
3
4
 
@@ -34,3 +35,4 @@ class <%= class_name.pluralize %>Controller < ApplicationController
34
35
  params.require(:<%= singular_name %>).permit(<%= attributes.map { |a| ':' + a.name }.join(', ') %>)
35
36
  end
36
37
  end
38
+ <% end -%>
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.dirname(__FILE__) + "/rest_api_generator"
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_controller"
4
+
5
+ module RestApiGenerator
6
+ class ApplicationController < ActionController::Base
7
+ end
8
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RestApiGenerator
4
+ class ChildResourceController < RestApiGenerator.parent_controller.constantize
5
+ include Orderable
6
+
7
+ before_action :set_parent_resource
8
+ before_action :set_resource, only: [:show, :update, :destroy]
9
+
10
+ def index
11
+ @resources = resources
12
+ @resources = @resources.filter_resource(params_for_filter) if resource_class.include?(Filterable)
13
+ @resources = @resources.order(ordering_params(params[:sort])) if params[:sort]
14
+ render json: @resources, status: :ok
15
+ end
16
+
17
+ def show
18
+ render json: @resource, status: :ok
19
+ end
20
+
21
+ def create
22
+ @resource = resources.create!(resource_created_params)
23
+ render json: @resource, status: :created
24
+ end
25
+
26
+ def update
27
+ @resource.update!(resource_updated_params)
28
+ render json: @resource, status: :ok
29
+ end
30
+
31
+ def destroy
32
+ @resource.destroy!
33
+ end
34
+
35
+ private
36
+
37
+ def resources
38
+ @parent_resource.send(resource_class.to_s.downcase.pluralize)
39
+ end
40
+
41
+ def parent_resource_class
42
+ parent_resource_by_controller_name
43
+ end
44
+
45
+ def resource_class
46
+ resource_by_controller_name
47
+ end
48
+
49
+ # Params
50
+ def resource_created_params
51
+ resource_params
52
+ end
53
+
54
+ def resource_updated_params
55
+ resource_params
56
+ end
57
+
58
+ def resource_params
59
+ params.require(resource_class.model_name.singular.to_sym).permit(resource_attributes)
60
+ end
61
+
62
+ def resource_attributes
63
+ resource_class.attribute_names.map(&:to_sym)
64
+ end
65
+
66
+ def params_for_filter
67
+ params.slice(*resource_class.filter_scopes)
68
+ end
69
+
70
+ # Before actions
71
+ def set_parent_resource
72
+ @parent_resource = parent_resource_class.find(parent_record_id)
73
+ end
74
+
75
+ def set_resource
76
+ @resource = resources.find(record_id)
77
+ end
78
+
79
+ # UsersController => User
80
+ def resource_by_controller_name(controller_name = self.class.to_s)
81
+ controller_name.split(Regexp.union(["Controller", "::"]))[-1].singularize.constantize
82
+ end
83
+
84
+ # Users::DevicesController => User
85
+ def parent_resource_by_controller_name(controller_name = self.class.to_s)
86
+ controller_name.split(Regexp.union(["Controller", "::"]))[-2].singularize.constantize
87
+ end
88
+
89
+ def parent_record_id
90
+ params.dig("#{parent_resource_class.to_s.downcase.singularize}_id")
91
+ end
92
+
93
+ def record_id
94
+ params.permit(:id)[:id]
95
+ end
96
+ end
97
+ end