rest-api-generator 0.1.0 → 0.1.2
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/Gemfile +1 -1
- data/Gemfile.lock +171 -44
- data/README.md +232 -64
- data/Rakefile +1 -1
- data/lib/generators/rest_api_generator/helpers.rb +30 -0
- data/lib/generators/rest_api_generator/resource_generator.rb +73 -13
- data/lib/generators/rest_api_generator/templates/child_api_controller.rb.tt +9 -8
- data/lib/generators/rest_api_generator/templates/child_api_spec.rb.tt +37 -34
- data/lib/generators/rest_api_generator/templates/implicit_child_resource_controller.rb.tt +4 -0
- data/lib/generators/rest_api_generator/templates/implicit_resource_controller.rb.tt +4 -0
- data/lib/generators/rest_api_generator/templates/rest_api_controller.rb.tt +3 -1
- data/lib/generators/rest_api_generator/templates/rest_api_spec.rb.tt +5 -5
- data/lib/rest-api-generator.rb +3 -0
- data/lib/rest_api_generator/application_controller.rb +8 -0
- data/lib/rest_api_generator/child_resource_controller.rb +97 -0
- data/lib/rest_api_generator/filterable.rb +30 -0
- data/lib/rest_api_generator/helpers/render.rb +1 -1
- data/lib/rest_api_generator/orderable.rb +30 -0
- data/lib/rest_api_generator/resource_controller.rb +73 -0
- data/lib/rest_api_generator/version.rb +1 -1
- data/lib/rest_api_generator.rb +11 -1
- data/rest-api-generator.gemspec +41 -0
- metadata +73 -11
- data/.rspec +0 -3
- data/.rubocop.yml +0 -23
- data/CODE_OF_CONDUCT.md +0 -84
- data/LICENSE.txt +0 -21
| @@ -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,89 @@ 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: ""
         | 
| 15 | 
            +
                class_option :father, type: :string, default: ""
         | 
| 12 16 |  | 
| 13 17 | 
             
                API_CONTROLLER_DIR_PATH = "app/controllers"
         | 
| 14 18 | 
             
                API_TEST_DIR_PATH = "spec/requests"
         | 
| 15 19 |  | 
| 16 20 | 
             
                def create_service_file
         | 
| 17 | 
            -
                   | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 21 | 
            +
                  create_model_files
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  # Create controller and specs
         | 
| 24 | 
            +
                  controller_path = "#{API_CONTROLLER_DIR_PATH}#{scope_path}/#{file_name.pluralize}_controller.rb"
         | 
| 25 | 
            +
                  controller_test_path = "#{API_TEST_DIR_PATH}#{scope_path}/#{file_name.pluralize}_controller_spec.rb"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  template controller_template, controller_path
         | 
| 28 | 
            +
                  template spec_controller_template, controller_test_path
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  if options["scope"].blank? && options["father"].blank?
         | 
| 31 | 
            +
                    route "resources :#{file_name.pluralize}"
         | 
| 25 32 | 
             
                  else
         | 
| 26 | 
            -
                     | 
| 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
         | 
| 33 | 
            +
                    log("You need to manually setup routes files for nested or scoped resource")
         | 
| 31 34 | 
             
                  end
         | 
| 32 35 | 
             
                end
         | 
| 33 36 |  | 
| 34 37 | 
             
                private
         | 
| 35 38 |  | 
| 39 | 
            +
                def scope_path
         | 
| 40 | 
            +
                  return "" if options["scope"].blank? && options["father"].blank?
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  if options["scope"].present? && options["father"].present?
         | 
| 43 | 
            +
                    "/" + option_to_path(options["scope"]) + "/" + option_to_path(options["father"])
         | 
| 44 | 
            +
                  else
         | 
| 45 | 
            +
                    "/" + option_to_path(options["scope"]) + option_to_path(options["father"])
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def scope_namespacing(&block)
         | 
| 50 | 
            +
                  content = capture(&block)
         | 
| 51 | 
            +
                  content = wrap_with_scope(content) if options["scope"].present? || options["father"].present?
         | 
| 52 | 
            +
                  concat(content)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def module_namespace
         | 
| 56 | 
            +
                  if options["scope"].present? && options["father"].present?
         | 
| 57 | 
            +
                    options["scope"] + "::" + options["father"]
         | 
| 58 | 
            +
                  else
         | 
| 59 | 
            +
                    options["scope"] + options["father"]
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def wrap_with_scope(content)
         | 
| 64 | 
            +
                  content = indent(content).chomp
         | 
| 65 | 
            +
                  "module #{module_namespace}\n#{content}\nend\n"
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def controller_template
         | 
| 69 | 
            +
                  if options["eject"]
         | 
| 70 | 
            +
                    if options["father"].present?
         | 
| 71 | 
            +
                      "child_api_controller.rb"
         | 
| 72 | 
            +
                    else
         | 
| 73 | 
            +
                      "rest_api_controller.rb"
         | 
| 74 | 
            +
                    end
         | 
| 75 | 
            +
                  elsif options["father"].present?
         | 
| 76 | 
            +
                    "implicit_child_resource_controller.rb"
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    "implicit_resource_controller.rb"
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def spec_controller_template
         | 
| 83 | 
            +
                  if options["father"].present?
         | 
| 84 | 
            +
                    "child_api_spec.rb"
         | 
| 85 | 
            +
                  else
         | 
| 86 | 
            +
                    "rest_api_spec.rb"
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def create_model_files
         | 
| 91 | 
            +
                  g = Rails::Generators::ModelGenerator.new([file_name, build_model_attributes])
         | 
| 92 | 
            +
                  g.destination_root = destination_root
         | 
| 93 | 
            +
                  g.invoke_all
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 36 96 | 
             
                def build_model_attributes
         | 
| 37 97 | 
             
                  model_attributes = []
         | 
| 38 98 | 
             
                  attributes.each do |attribute|
         | 
| @@ -1,9 +1,10 @@ | |
| 1 | 
            +
            <% scope_namespacing do -%>
         | 
| 1 2 | 
             
            class <%= class_name.pluralize %>Controller < ApplicationController
         | 
| 2 | 
            -
              before_action :set_<%= options[' | 
| 3 | 
            +
              before_action :set_<%= options['father'].downcase.singularize %>
         | 
| 3 4 | 
             
              before_action :set_<%= singular_name %>, only: %i[ show update destroy ]
         | 
| 4 5 |  | 
| 5 6 | 
             
              def index
         | 
| 6 | 
            -
                @<%= plural_name %> = @<%= options[' | 
| 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[' | 
| 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[' | 
| 32 | 
            -
                @<%= options[' | 
| 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[' | 
| 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 -%>
         | 
| @@ -1,14 +1,36 @@ | |
| 1 | 
            -
            require  | 
| 1 | 
            +
            require "rails_helper"
         | 
| 2 2 |  | 
| 3 | 
            -
            RSpec.describe "<%=class_name %>", type: :request do
         | 
| 3 | 
            +
            RSpec.describe "<%= class_name %>", type: :request do
         | 
| 4 4 | 
             
              let(:valid_attributes) { attributes_for(:<%= singular_table_name %>) }
         | 
| 5 5 |  | 
| 6 | 
            -
              describe " | 
| 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
         | 
| 7 29 | 
             
                context "with valid parameters" do
         | 
| 8 | 
            -
                   | 
| 9 | 
            -
             | 
| 30 | 
            +
                  let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
         | 
| 31 | 
            +
                  it "creates a new <%= singular_name %>" do
         | 
| 10 32 | 
             
                    expect do
         | 
| 11 | 
            -
                      post " | 
| 33 | 
            +
                      post "<%= spec_routes[:create] %>",
         | 
| 12 34 | 
             
                           params: { <%= singular_name %>: valid_attributes }
         | 
| 13 35 | 
             
                    end.to change(<%= class_name %>, :count).by(1)
         | 
| 14 36 | 
             
                  end
         | 
| @@ -16,44 +38,25 @@ RSpec.describe "<%=class_name %>", type: :request do | |
| 16 38 | 
             
              end
         | 
| 17 39 |  | 
| 18 40 | 
             
              describe "PATCH /<%= plural_name %>" do
         | 
| 19 | 
            -
                let(:<%= options[' | 
| 20 | 
            -
                let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options[' | 
| 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 %>)}
         | 
| 21 43 |  | 
| 22 | 
            -
                it "updates an <%=singular_name %>" do
         | 
| 23 | 
            -
                    patch " | 
| 44 | 
            +
                it "updates an <%= singular_name %>" do
         | 
| 45 | 
            +
                    patch "<%= spec_routes[:update] %>",
         | 
| 24 46 | 
             
                        params: { <%= singular_name %>: valid_attributes }
         | 
| 25 47 | 
             
                    expect(response).to have_http_status(:success)
         | 
| 26 48 | 
             
                end
         | 
| 27 49 | 
             
              end
         | 
| 28 50 |  | 
| 29 51 | 
             
              describe "DELETE /<%= singular_name %>" do
         | 
| 30 | 
            -
                let(:<%= options[' | 
| 52 | 
            +
                let(:<%= options['father'].downcase.singularize %>) { create(:<%= options['father'].downcase.singularize %>) }
         | 
| 31 53 |  | 
| 32 | 
            -
                it "deletes an <%=singular_name %>" do
         | 
| 33 | 
            -
                  <%= singular_table_name %> = create(:<%=singular_table_name %>, <%= options[' | 
| 54 | 
            +
                it "deletes an <%= singular_name %>" do
         | 
| 55 | 
            +
                  <%= singular_table_name %> = create(:<%=singular_table_name %>, <%= options['father'].downcase.singularize %>: <%= options['father'].downcase.singularize %>)
         | 
| 34 56 | 
             
                  expect do
         | 
| 35 | 
            -
                    delete " | 
| 57 | 
            +
                    delete "<%= spec_routes[:delete] %>"
         | 
| 36 58 | 
             
                  end.to change(<%= class_name %>, :count).by(-1)
         | 
| 37 59 | 
             
                end
         | 
| 38 60 | 
             
              end
         | 
| 39 61 |  | 
| 40 | 
            -
             | 
| 41 | 
            -
                let(:<%= options['scope'].downcase %>) {create(:<%= options['scope'].downcase %>)}
         | 
| 42 | 
            -
                let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options['scope'].downcase %>: <%= options['scope'].downcase %>)}
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                it "gets an <%=singular_name %>" do
         | 
| 45 | 
            -
                  get "/<%= options['scope'].downcase.pluralize %>/#{<%= options['scope'].downcase %>.id}/<%= plural_name %>/#{<%= singular_name %>.id}"
         | 
| 46 | 
            -
                  expect(response).to be_successful
         | 
| 47 | 
            -
                end
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              describe "GET /<%= plural_name %>" do
         | 
| 51 | 
            -
                let(:<%= options['scope'].downcase %>) {create(:<%= options['scope'].downcase %>)}
         | 
| 52 | 
            -
                let(:<%= singular_table_name %>) { create(:<%=singular_table_name %>, <%= options['scope'].downcase %>: <%= options['scope'].downcase %>) }
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                it "renders a successful response" do
         | 
| 55 | 
            -
                  get "/<%= options['scope'].downcase.pluralize %>/#{<%= options['scope'].downcase %>.id}/<%= plural_name %>"
         | 
| 56 | 
            -
                  expect(response).to be_successful
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
              end
         | 
| 59 | 
            -
            end
         | 
| 62 | 
            +
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 | 
            +
            <% scope_namespacing do -%>
         | 
| 1 2 | 
             
            class <%= class_name.pluralize %>Controller < ApplicationController
         | 
| 2 | 
            -
              before_action :set_<%= singular_name %>, only: %i[ | 
| 3 | 
            +
              before_action :set_<%= singular_name %>, only: %i[show update destroy]
         | 
| 3 4 |  | 
| 4 5 | 
             
              def index
         | 
| 5 6 | 
             
                @<%= singular_name %> = <%= class_name %>.all
         | 
| @@ -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 -%>
         | 
| @@ -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 " | 
| 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 " | 
| 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 " | 
| 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 " | 
| 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 " | 
| 43 | 
            +
                    delete "<%= spec_routes[:delete] %>"
         | 
| 44 44 | 
             
                  end.to change(<%= class_name %>, :count).by(-1)
         | 
| 45 45 | 
             
                end
         | 
| 46 46 | 
             
              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
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "active_support/concern"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module RestApiGenerator
         | 
| 6 | 
            +
              module Filterable
         | 
| 7 | 
            +
                extend ActiveSupport::Concern
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                included do
         | 
| 10 | 
            +
                  @filter_scopes ||= []
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                module ClassMethods
         | 
| 14 | 
            +
                  attr_reader :filter_scopes
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def filter_scope(name, *args)
         | 
| 17 | 
            +
                    scope name, *args
         | 
| 18 | 
            +
                    @filter_scopes << name.to_s.gsub("filter_by_", "").to_sym
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def filter_resource(params)
         | 
| 22 | 
            +
                    results = where(nil)
         | 
| 23 | 
            +
                    params.each do |key, value|
         | 
| 24 | 
            +
                      results = results.public_send("filter_by_#{key}", value) if value.present?
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                    results
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "active_support"
         | 
| 4 | 
            +
            require "active_support/concern"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module RestApiGenerator
         | 
| 7 | 
            +
              module Orderable
         | 
| 8 | 
            +
                extend ActiveSupport::Concern
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                SORT_ORDER = { " " => :asc, "+" => :asc, "-" => :desc }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # Returns params for order in active record order syntax
         | 
| 13 | 
            +
                # GET /api/v1/transactions?sort=-amount
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # ordering_params(params) # => { amount: :desc }
         | 
| 16 | 
            +
                def ordering_params(order_params)
         | 
| 17 | 
            +
                  ordering = {}
         | 
| 18 | 
            +
                  if order_params
         | 
| 19 | 
            +
                    sorted_params = order_params.split(",")
         | 
| 20 | 
            +
                    sorted_params.each do |attr|
         | 
| 21 | 
            +
                      sort_sign = /\A[ +-]/.match?(attr) ? attr.slice!(0) : "+"
         | 
| 22 | 
            +
                      if resource_class.attribute_names.include?(attr)
         | 
| 23 | 
            +
                        ordering[attr] = SORT_ORDER[sort_sign]
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  ordering
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RestApiGenerator
         | 
| 4 | 
            +
              class ResourceController < RestApiGenerator.parent_controller.constantize
         | 
| 5 | 
            +
                include Orderable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                before_action :set_resource, only: [:show, :update, :destroy]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def index
         | 
| 10 | 
            +
                  @resources = resource_class.all
         | 
| 11 | 
            +
                  @resources = @resources.filter_resource(params_for_filter) if resource_class.include?(Filterable)
         | 
| 12 | 
            +
                  @resources = @resources.order(ordering_params(params[:sort])) if params[:sort]
         | 
| 13 | 
            +
                  render json: @resources, status: :ok
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def show
         | 
| 17 | 
            +
                  render json: @resource, status: :ok
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def create
         | 
| 21 | 
            +
                  @resource = resource_class.create!(resource_created_params)
         | 
| 22 | 
            +
                  render json: @resource, status: :created
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def update
         | 
| 26 | 
            +
                  @resource.update!(resource_updated_params)
         | 
| 27 | 
            +
                  render json: @resource, status: :ok
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def destroy
         | 
| 31 | 
            +
                  @resource.destroy!
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                private
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def params_for_filter
         | 
| 37 | 
            +
                  params.slice(*resource_class.filter_scopes)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def resource_class
         | 
| 41 | 
            +
                  resource_by_controller_name
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def resource_created_params
         | 
| 45 | 
            +
                  resource_params
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def resource_updated_params
         | 
| 49 | 
            +
                  resource_params
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def resource_params
         | 
| 53 | 
            +
                  params.require(resource_class.model_name.singular.to_sym).permit(resource_attributes)
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def resource_attributes
         | 
| 57 | 
            +
                  resource_class.attribute_names.map(&:to_sym)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def set_resource
         | 
| 61 | 
            +
                  @resource = resource_class.find(record_id)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                # UsersController => User
         | 
| 65 | 
            +
                def resource_by_controller_name(controller_name = self.class.to_s)
         | 
| 66 | 
            +
                  controller_name.split(Regexp.union(["Controller", "::"]))[-1].singularize.constantize
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def record_id
         | 
| 70 | 
            +
                  params.permit(:id)[:id]
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
    
        data/lib/rest_api_generator.rb
    CHANGED
    
    | @@ -1,11 +1,21 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require "rails"
         | 
| 3 4 | 
             
            require_relative "rest_api_generator/version"
         | 
| 5 | 
            +
            require_relative "rest_api_generator/application_controller"
         | 
| 4 6 | 
             
            require_relative "rest_api_generator/error_handler"
         | 
| 5 7 | 
             
            require_relative "rest_api_generator/custom_error"
         | 
| 6 8 | 
             
            require_relative "rest_api_generator/helpers/render"
         | 
| 9 | 
            +
            require_relative "rest_api_generator/filterable"
         | 
| 10 | 
            +
            require_relative "rest_api_generator/orderable"
         | 
| 7 11 |  | 
| 8 12 | 
             
            module RestApiGenerator
         | 
| 9 13 | 
             
              class Error < StandardError; end
         | 
| 10 | 
            -
             | 
| 14 | 
            +
             | 
| 15 | 
            +
              def self.parent_controller
         | 
| 16 | 
            +
                "RestApiGenerator::ApplicationController"
         | 
| 17 | 
            +
              end
         | 
| 11 18 | 
             
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            require_relative "rest_api_generator/resource_controller"
         | 
| 21 | 
            +
            require_relative "rest_api_generator/child_resource_controller"
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            $:.push File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative "lib/rest_api_generator/version"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name = "rest-api-generator"
         | 
| 8 | 
            +
              spec.version = RestApiGenerator::VERSION
         | 
| 9 | 
            +
              spec.authors = ["PedroAugustoRamalhoDuarte"]
         | 
| 10 | 
            +
              spec.email = ["pedro_aduarte@aluno.unb.br"]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              spec.summary = "Build a Ruby on Rails REST API faster"
         | 
| 13 | 
            +
              spec.description = "This gem helps you to build a Ruby on Rails REST API faster, using a scaffold-like generator that follows the best practices."
         | 
| 14 | 
            +
              spec.homepage = "https://github.com/SwitchDreams/rest-api-generator"
         | 
| 15 | 
            +
              spec.license = "MIT"
         | 
| 16 | 
            +
              spec.required_ruby_version = ">= 2.6.0"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              spec.metadata["allowed_push_host"] = "https://rubygems.org/"
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              spec.metadata["homepage_uri"] = spec.homepage
         | 
| 21 | 
            +
              spec.metadata["source_code_uri"] = "https://github.com/SwitchDreams/rest-api-generator"
         | 
| 22 | 
            +
              spec.metadata["changelog_uri"] = "https://github.com/SwitchDreams/rest-api-generator"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              spec.files = Dir["{bin,sig,lib,public}/**/*", "MIT-LICENSE", "Rakefile", "README.md", "rest-api-generator.gemspec",
         | 
| 25 | 
            +
                               "Gemfile", "Gemfile.lock"]
         | 
| 26 | 
            +
              spec.bindir = "exe"
         | 
| 27 | 
            +
              spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         | 
| 28 | 
            +
              spec.require_paths = ["lib"]
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              # For more information and examples about making a new gem, check out our
         | 
| 31 | 
            +
              # guide at: https://bundler.io/guides/creating_gem.html
         | 
| 32 | 
            +
              spec.metadata["rubygems_mfa_required"] = "true"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              spec.add_dependency "rails", ">= 5.0"
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              spec.add_development_dependency 'ammeter', '~> 1.1.5'
         | 
| 37 | 
            +
              spec.add_development_dependency 'rspec-rails', '~> 6.0.0'
         | 
| 38 | 
            +
              spec.add_development_dependency 'sqlite3'
         | 
| 39 | 
            +
              spec.add_development_dependency 'database_cleaner'
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            end
         |