From 11a525a3a9dd63d8312b7c63a198d04c0b6771a2 Mon Sep 17 00:00:00 2001 From: ps-ruby Date: Thu, 15 Dec 2022 22:07:25 +0600 Subject: [PATCH] Initial implementation --- Gemfile.lock | 16 +-- .../simple_singletons_controller.rb | 69 +++++++++++ .../simple_singletons_controller.rb | 55 +++++++++ app/models/scaffolding/completely_concrete.rb | 5 + .../completely_concrete/simple_singleton.rb | 24 ++++ .../simple_singletons/_breadcrumbs.html.erb | 8 ++ .../simple_singletons/_form.html.erb | 17 +++ .../simple_singletons/_index.html.erb | 81 ++++++++++++ .../simple_singletons/_menu_item.html.erb | 10 ++ .../simple_singletons/edit.html.erb | 12 ++ .../simple_singletons/index.html.erb | 6 + .../simple_singletons/new.html.erb | 12 ++ .../simple_singletons/show.html.erb | 34 ++++++ app/views/api/v1/open_api/index.yaml.erb | 2 + .../_simple_singleton.json.jbuilder | 7 ++ .../simple_singletons/index.json.jbuilder | 1 + .../simple_singletons/show.json.jbuilder | 1 + .../simple_singletons.en.yml | 91 ++++++++++++++ config/models/roles.yml | 2 + config/routes.rb | 16 ++- config/routes/api/v1.rb | 14 +++ ...g_completely_concrete_simple_singletons.rb | 10 ++ db/schema.rb | 11 +- .../simple_singletons_controller_test.rb | 115 ++++++++++++++++++ .../completely_concrete/simple_singletons.rb | 6 + .../simple_singleton_test.rb | 7 ++ 26 files changed, 623 insertions(+), 9 deletions(-) create mode 100644 app/controllers/account/scaffolding/completely_concrete/simple_singletons_controller.rb create mode 100644 app/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller.rb create mode 100644 app/models/scaffolding/completely_concrete.rb create mode 100644 app/models/scaffolding/completely_concrete/simple_singleton.rb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/_breadcrumbs.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/_form.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/_index.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/_menu_item.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/edit.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/index.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/new.html.erb create mode 100644 app/views/account/scaffolding/completely_concrete/simple_singletons/show.html.erb create mode 100644 app/views/api/v1/scaffolding/completely_concrete/simple_singletons/_simple_singleton.json.jbuilder create mode 100644 app/views/api/v1/scaffolding/completely_concrete/simple_singletons/index.json.jbuilder create mode 100644 app/views/api/v1/scaffolding/completely_concrete/simple_singletons/show.json.jbuilder create mode 100644 config/locales/en/scaffolding/completely_concrete/simple_singletons.en.yml create mode 100644 db/migrate/20221215152529_create_scaffolding_completely_concrete_simple_singletons.rb create mode 100644 test/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller_test.rb create mode 100644 test/factories/scaffolding/completely_concrete/simple_singletons.rb create mode 100644 test/models/scaffolding/completely_concrete/simple_singleton_test.rb diff --git a/Gemfile.lock b/Gemfile.lock index b2cc3f60c..190255f9c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -115,7 +115,7 @@ GEM bootsnap (1.15.0) msgpack (~> 1.2) builder (3.2.4) - bullet_train (1.1.9) + bullet_train (1.1.10) awesome_print bullet_train-fields bullet_train-has_uuid @@ -187,7 +187,7 @@ GEM rails (>= 7.0.0) bullet_train-super_load_and_authorize_resource (1.0.1) rails (>= 6.0.0) - bullet_train-super_scaffolding (1.1.14) + bullet_train-super_scaffolding (1.1.15) bullet_train indefinite_article rails (>= 6.0.0) @@ -215,7 +215,7 @@ GEM charlock_holmes (0.7.7) chronic (0.10.2) chunky_png (1.4.0) - cloudinary (1.23.0) + cloudinary (1.24.0) aws_cf_signer rest-client (>= 2.0.0) code_analyzer (0.5.5) @@ -230,6 +230,7 @@ GEM addressable cssbundling-rails (1.1.1) railties (>= 6.0.0) + date (3.3.1) debug (1.7.0) irb (>= 1.5.0) reline (>= 0.3.1) @@ -338,11 +339,12 @@ GEM minitest (>= 5.0) msgpack (1.6.0) multi_xml (0.6.0) - net-imap (0.3.1) + net-imap (0.3.2) + date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.1.3) + net-protocol (0.2.1) timeout net-smtp (0.3.3) net-protocol @@ -405,7 +407,7 @@ GEM pry-stack_explorer (0.6.1) binding_of_caller (~> 1.0) pry (~> 0.13) - public_suffix (5.0.0) + public_suffix (5.0.1) puma (6.0.0) nio4r (~> 2.0) pwned (2.0.2) @@ -533,7 +535,7 @@ GEM stripe (8.0.0) thor (1.2.1) thread-local (1.1.0) - timeout (0.3.0) + timeout (0.3.1) turbo-rails (1.3.2) actionpack (>= 6.0.0) activejob (>= 6.0.0) diff --git a/app/controllers/account/scaffolding/completely_concrete/simple_singletons_controller.rb b/app/controllers/account/scaffolding/completely_concrete/simple_singletons_controller.rb new file mode 100644 index 000000000..cd88d2dbf --- /dev/null +++ b/app/controllers/account/scaffolding/completely_concrete/simple_singletons_controller.rb @@ -0,0 +1,69 @@ +class Account::Scaffolding::CompletelyConcrete::SimpleSingletonsController < Account::ApplicationController + account_load_and_authorize_resource :simple_singleton, through: :absolutely_abstract_creative_concept, through_association: :completely_concrete_simple_singletons + + # GET /account/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons + # GET /account/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons.json + def index + delegate_json_to_api + end + + # GET /account/scaffolding/completely_concrete/simple_singletons/:id + # GET /account/scaffolding/completely_concrete/simple_singletons/:id.json + def show + delegate_json_to_api + end + + # GET /account/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons/new + def new + end + + # GET /account/scaffolding/completely_concrete/simple_singletons/:id/edit + def edit + end + + # POST /account/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons + # POST /account/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons.json + def create + respond_to do |format| + if @simple_singleton.save + format.html { redirect_to [:account, @absolutely_abstract_creative_concept, :completely_concrete_simple_singletons], notice: I18n.t("scaffolding/completely_concrete/simple_singletons.notifications.created") } + format.json { render :show, status: :created, location: [:account, @simple_singleton] } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @simple_singleton.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /account/scaffolding/completely_concrete/simple_singletons/:id + # PATCH/PUT /account/scaffolding/completely_concrete/simple_singletons/:id.json + def update + respond_to do |format| + if @simple_singleton.update(simple_singleton_params) + format.html { redirect_to [:account, @simple_singleton], notice: I18n.t("scaffolding/completely_concrete/simple_singletons.notifications.updated") } + format.json { render :show, status: :ok, location: [:account, @simple_singleton] } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @simple_singleton.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /account/scaffolding/completely_concrete/simple_singletons/:id + # DELETE /account/scaffolding/completely_concrete/simple_singletons/:id.json + def destroy + @simple_singleton.destroy + respond_to do |format| + format.html { redirect_to [:account, @absolutely_abstract_creative_concept, :completely_concrete_simple_singletons], notice: I18n.t("scaffolding/completely_concrete/simple_singletons.notifications.destroyed") } + format.json { head :no_content } + end + end + + private + + include strong_parameters_from_api + + def process_params(strong_params) + # 🚅 super scaffolding will insert processing for new fields above this line. + end +end diff --git a/app/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller.rb b/app/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller.rb new file mode 100644 index 000000000..b4332491c --- /dev/null +++ b/app/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller.rb @@ -0,0 +1,55 @@ +class Api::V1::Scaffolding::CompletelyConcrete::SimpleSingletonsController < Api::V1::ApplicationController + account_load_and_authorize_resource :simple_singleton, through: :absolutely_abstract_creative_concept, through_association: :completely_concrete_simple_singletons + + # GET /api/v1/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons + def index + end + + # GET /api/v1/scaffolding/completely_concrete/simple_singletons/:id + def show + end + + # POST /api/v1/scaffolding/absolutely_abstract/creative_concepts/:absolutely_abstract_creative_concept_id/completely_concrete/simple_singletons + def create + if @simple_singleton.save + render :show, status: :created, location: [:api, :v1, @simple_singleton] + else + render json: @simple_singleton.errors, status: :unprocessable_entity + end + end + + # PATCH/PUT /api/v1/scaffolding/completely_concrete/simple_singletons/:id + def update + if @simple_singleton.update(simple_singleton_params) + render :show + else + render json: @simple_singleton.errors, status: :unprocessable_entity + end + end + + # DELETE /api/v1/scaffolding/completely_concrete/simple_singletons/:id + def destroy + @simple_singleton.destroy + end + + private + + module StrongParameters + # Only allow a list of trusted parameters through. + def simple_singleton_params + strong_params = params.require(:scaffolding_completely_concrete_simple_singleton).permit( + *permitted_fields, + :name, + # 🚅 super scaffolding will insert new fields above this line. + *permitted_arrays, + # 🚅 super scaffolding will insert new arrays above this line. + ) + + process_params(strong_params) + + strong_params + end + end + + include StrongParameters +end diff --git a/app/models/scaffolding/completely_concrete.rb b/app/models/scaffolding/completely_concrete.rb new file mode 100644 index 000000000..fc9482c17 --- /dev/null +++ b/app/models/scaffolding/completely_concrete.rb @@ -0,0 +1,5 @@ +module Scaffolding::CompletelyConcrete + def self.table_name_prefix + "scaffolding_completely_concrete_" + end +end diff --git a/app/models/scaffolding/completely_concrete/simple_singleton.rb b/app/models/scaffolding/completely_concrete/simple_singleton.rb new file mode 100644 index 000000000..2b2797f97 --- /dev/null +++ b/app/models/scaffolding/completely_concrete/simple_singleton.rb @@ -0,0 +1,24 @@ +class Scaffolding::CompletelyConcrete::SimpleSingleton < ApplicationRecord + # 🚅 add concerns above. + + # 🚅 add attribute accessors above. + + belongs_to :absolutely_abstract_creative_concept, class_name: "Scaffolding::AbsolutelyAbstract::CreativeConcept" + # 🚅 add belongs_to associations above. + + # 🚅 add has_many associations above. + + has_one :team, through: :absolutely_abstract_creative_concept + # 🚅 add has_one associations above. + + # 🚅 add scopes above. + + validates :name, presence: true + # 🚅 add validations above. + + # 🚅 add callbacks above. + + # 🚅 add delegations above. + + # 🚅 add methods above. +end diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/_breadcrumbs.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/_breadcrumbs.html.erb new file mode 100644 index 000000000..b21ac3a32 --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/_breadcrumbs.html.erb @@ -0,0 +1,8 @@ +<% simple_singleton ||= @simple_singleton %> +<% absolutely_abstract_creative_concept ||= @absolutely_abstract_creative_concept || simple_singleton&.absolutely_abstract_creative_concept %> +<%= render 'account/scaffolding/absolutely_abstract/creative_concepts/breadcrumbs', creative_concept: absolutely_abstract_creative_concept %> +<%= render 'account/shared/breadcrumb', label: t('.label'), url: [:account, absolutely_abstract_creative_concept, :completely_concrete_simple_singletons] %> +<% if simple_singleton&.persisted? %> + <%= render 'account/shared/breadcrumb', label: simple_singleton.label_string, url: [:account, simple_singleton] %> +<% end %> +<%= render 'account/shared/breadcrumbs/actions', only_for: 'scaffolding/completely_concrete/simple_singletons' %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/_form.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/_form.html.erb new file mode 100644 index 000000000..a92a9d5aa --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/_form.html.erb @@ -0,0 +1,17 @@ +<% cancel_path ||= simple_singleton.persisted? ? [:account, simple_singleton] : [:account, @absolutely_abstract_creative_concept, :completely_concrete_simple_singletons] %> + +<%= form_with model: simple_singleton, url: (simple_singleton.persisted? ? [:account, simple_singleton] : [:account, @absolutely_abstract_creative_concept, :completely_concrete_simple_singletons]), local: true, class: 'form' do |form| %> + <%= render "shared/limits/form", form: form, cancel_path: cancel_path do %> + <%= render 'account/shared/forms/errors', form: form %> + + <% with_field_settings form: form do %> + <%= render 'shared/fields/text_field', method: :name, options: {autofocus: true} %> + <%# 🚅 super scaffolding will insert new fields above this line. %> + <% end %> + +
+ <%= form.submit (form.object.persisted? ? t('.buttons.update') : t('.buttons.create')), class: "button" %> + <%= link_to t('global.buttons.cancel'), cancel_path, class: "button-secondary" %> +
+ <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/_index.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/_index.html.erb new file mode 100644 index 000000000..622e2afb1 --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/_index.html.erb @@ -0,0 +1,81 @@ +<% absolutely_abstract_creative_concept = @absolutely_abstract_creative_concept || @creative_concept %> +<% context ||= absolutely_abstract_creative_concept %> +<% collection ||= :completely_concrete_simple_singletons %> +<% hide_actions ||= false %> +<% hide_back ||= false %> + +<% simple_singletons = simple_singletons.order(:id) unless has_order?(simple_singletons) %> +<% pagy, simple_singletons = pagy(simple_singletons, page_param: :simple_singletons_page) %> + +<%= action_model_select_controller do %> + <%= updates_for context, collection do %> + <%= render 'account/shared/box', pagy: pagy do |p| %> + <% p.content_for :title, t(".contexts.#{context.class.name.underscore}.header") %> + <% p.content_for :description do %> + <%= t(".contexts.#{context.class.name.underscore}.description#{"_empty" unless simple_singletons.any?}") %> + <%= render "shared/limits/index", model: simple_singletons.model %> + <% end %> + + <% p.content_for :table do %> + <% if simple_singletons.any? %> + + + + <%= render "shared/tables/select_all" %> + + <%# 🚅 super scaffolding will insert new field headers above this line. %> + + + + + + <% simple_singletons.each do |simple_singleton| %> + <% with_attribute_settings object: simple_singleton do %> + + <%= render "shared/tables/checkbox", object: simple_singleton %> + + <%# 🚅 super scaffolding will insert new fields above this line. %> + + + + <% end %> + <% end %> + +
<%= t('.fields.name.heading') %><%= t('.fields.created_at.heading') %>
<%= render 'shared/attributes/text', attribute: :name, url: [:account, simple_singleton] %><%= render 'shared/attributes/date_and_time', attribute: :created_at %> + <% unless hide_actions %> + <% if can? :edit, simple_singleton %> + <%= link_to t('.buttons.shorthand.edit'), [:edit, :account, simple_singleton], class: 'button-secondary button-smaller' %> + <% end %> + <% if can? :destroy, simple_singleton %> + <%= button_to t('.buttons.shorthand.destroy'), [:account, simple_singleton], method: :delete, data: { confirm: t('.buttons.confirmations.destroy', model_locales(simple_singleton)) }, class: 'button-secondary button-smaller' %> + <% end %> + <%# 🚅 super scaffolding will insert new action model buttons above this line. %> + <% end %> +
+ <% end %> + <% end %> + + <% p.content_for :actions do %> + <% unless hide_actions %> + <% if context == absolutely_abstract_creative_concept %> + <% if can? :create, Scaffolding::CompletelyConcrete::SimpleSingleton.new(absolutely_abstract_creative_concept: absolutely_abstract_creative_concept) %> + <%= link_to t('.buttons.new'), [:new, :account, absolutely_abstract_creative_concept, :completely_concrete_simple_singleton], class: "#{first_button_primary(:completely_concrete_simple_singleton)} new" %> + <% end %> + <% end %> + + <%# 🚅 super scaffolding will insert new targets one parent action model buttons above this line. %> + <%# 🚅 super scaffolding will insert new bulk action model buttons above this line. %> + <%= render "shared/bulk_action_select" %> + + <% unless hide_back %> + <%= link_to t('global.buttons.back'), [:account, context], class: "#{first_button_primary(:completely_concrete_simple_singleton)} back" %> + <% end %> + <% end %> + <% end %> + + <% p.content_for :raw_footer do %> + <%# 🚅 super scaffolding will insert new action model index views above this line. %> + <% end %> + <% end %> + <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/_menu_item.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/_menu_item.html.erb new file mode 100644 index 000000000..591055f7b --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/_menu_item.html.erb @@ -0,0 +1,10 @@ +<% if can? :read, Scaffolding::CompletelyConcrete::SimpleSingleton.new(team: current_team) %> + <%= render 'account/shared/menu/item', { + url: main_app.polymorphic_path([:account, current_team, :scaffolding_completely_concrete_simple_singletons]), + label: t('scaffolding/completely_concrete/simple_singletons.navigation.label'), + } do |p| %> + <% p.content_for :icon do %> + + <% end %> + <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/edit.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/edit.html.erb new file mode 100644 index 000000000..47ff08517 --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/edit.html.erb @@ -0,0 +1,12 @@ +<%= render 'account/shared/page' do |p| %> + <% p.content_for :title, t('.section') %> + <% p.content_for :body do %> + <%= render 'account/shared/box', divider: true do |p| %> + <% p.content_for :title, t('.header') %> + <% p.content_for :description, t('.description') %> + <% p.content_for :body do %> + <%= render 'form', simple_singleton: @simple_singleton %> + <% end %> + <% end %> + <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/index.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/index.html.erb new file mode 100644 index 000000000..107aff535 --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/index.html.erb @@ -0,0 +1,6 @@ +<%= render 'account/shared/page' do |p| %> + <% p.content_for :title, t('.section') %> + <% p.content_for :body do %> + <%= render 'index', simple_singletons: @simple_singletons %> + <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/new.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/new.html.erb new file mode 100644 index 000000000..47ff08517 --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/new.html.erb @@ -0,0 +1,12 @@ +<%= render 'account/shared/page' do |p| %> + <% p.content_for :title, t('.section') %> + <% p.content_for :body do %> + <%= render 'account/shared/box', divider: true do |p| %> + <% p.content_for :title, t('.header') %> + <% p.content_for :description, t('.description') %> + <% p.content_for :body do %> + <%= render 'form', simple_singleton: @simple_singleton %> + <% end %> + <% end %> + <% end %> +<% end %> diff --git a/app/views/account/scaffolding/completely_concrete/simple_singletons/show.html.erb b/app/views/account/scaffolding/completely_concrete/simple_singletons/show.html.erb new file mode 100644 index 000000000..c53842baa --- /dev/null +++ b/app/views/account/scaffolding/completely_concrete/simple_singletons/show.html.erb @@ -0,0 +1,34 @@ +<%= render 'account/shared/page' do |p| %> + <% p.content_for :title, t('.section') %> + <% p.content_for :body do %> + <%= updates_for @simple_singleton do %> + <%= render 'account/shared/box', divider: true do |p| %> + <% p.content_for :title, t('.header') %> + <% p.content_for :description do %> + <%= t('.description') %> + <%= t('.manage_description') if can? :manage, @simple_singleton %> + <% end %> + + <% p.content_for :body do %> + <% with_attribute_settings object: @simple_singleton, strategy: :label do %> + <%= render 'shared/attributes/text', attribute: :name %> + <%# 🚅 super scaffolding will insert new fields above this line. %> + <% end %> + <% end %> + + <% p.content_for :actions do %> + <%= link_to t('.buttons.edit'), [:edit, :account, @simple_singleton], class: first_button_primary if can? :edit, @simple_singleton %> + <%# 🚅 super scaffolding will insert new action model buttons above this line. %> + <%= button_to t('.buttons.destroy'), [:account, @simple_singleton], method: :delete, class: first_button_primary, data: { confirm: t('.buttons.confirmations.destroy', model_locales(@simple_singleton)) } if can? :destroy, @simple_singleton %> + <%= link_to t('global.buttons.back'), [:account, @absolutely_abstract_creative_concept, :completely_concrete_simple_singletons], class: first_button_primary %> + <% end %> + + <% p.content_for :raw_footer do %> + <%# 🚅 super scaffolding will insert new action model index views above this line. %> + <% end %> + <% end %> + <% end %> + + <%# 🚅 super scaffolding will insert new children above this line. %> + <% end %> +<% end %> diff --git a/app/views/api/v1/open_api/index.yaml.erb b/app/views/api/v1/open_api/index.yaml.erb index e885d9586..258f54c01 100644 --- a/app/views/api/v1/open_api/index.yaml.erb +++ b/app/views/api/v1/open_api/index.yaml.erb @@ -19,6 +19,7 @@ components: <%= automatic_components_for User %> <%= automatic_components_for Webhooks::Outgoing::Endpoint %> <%= automatic_components_for Scaffolding::CompletelyConcrete::TangibleThing unless scaffolding_things_disabled? %> + <%= automatic_components_for Scaffolding::CompletelyConcrete::SimpleSingleton %> <%# 🚅 super scaffolding will insert new components above this line. %> parameters: id: @@ -50,4 +51,5 @@ paths: <%= paths_for User %> <%= automatic_paths_for Webhooks::Outgoing::Endpoint, Team %> <%= automatic_paths_for Scaffolding::CompletelyConcrete::TangibleThing, Scaffolding::AbsolutelyAbstract::CreativeConcept unless scaffolding_things_disabled? %> + <%= automatic_paths_for Scaffolding::CompletelyConcrete::SimpleSingleton, Scaffolding::AbsolutelyAbstract::CreativeConcept %> <%# 🚅 super scaffolding will insert new paths above this line. %> diff --git a/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/_simple_singleton.json.jbuilder b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/_simple_singleton.json.jbuilder new file mode 100644 index 000000000..aa12351f6 --- /dev/null +++ b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/_simple_singleton.json.jbuilder @@ -0,0 +1,7 @@ +json.extract! simple_singleton, + :id, + :absolutely_abstract_creative_concept_id, + :name, + # 🚅 super scaffolding will insert new fields above this line. + :created_at, + :updated_at diff --git a/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/index.json.jbuilder b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/index.json.jbuilder new file mode 100644 index 000000000..8170ba642 --- /dev/null +++ b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @simple_singletons, partial: "api/v1/scaffolding/completely_concrete/simple_singletons/simple_singleton", as: :simple_singleton diff --git a/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/show.json.jbuilder b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/show.json.jbuilder new file mode 100644 index 000000000..e35068814 --- /dev/null +++ b/app/views/api/v1/scaffolding/completely_concrete/simple_singletons/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "api/v1/scaffolding/completely_concrete/simple_singletons/simple_singleton", simple_singleton: @simple_singleton diff --git a/config/locales/en/scaffolding/completely_concrete/simple_singletons.en.yml b/config/locales/en/scaffolding/completely_concrete/simple_singletons.en.yml new file mode 100644 index 000000000..acd41dfc6 --- /dev/null +++ b/config/locales/en/scaffolding/completely_concrete/simple_singletons.en.yml @@ -0,0 +1,91 @@ +en: + scaffolding/completely_concrete/simple_singletons: &simple_singletons + label: &label Simple Singletons + breadcrumbs: + label: *label + navigation: + label: *label + icon: fal fa-puzzle-piece + buttons: &buttons + new: Add New Simple Singleton + create: Create Simple Singleton + edit: Edit Simple Singleton + update: Update Simple Singleton + destroy: Remove Simple Singleton + shorthand: + edit: Edit + destroy: Delete + confirmations: + # TODO customize for your use-case. + destroy: Are you sure you want to remove %{simple_singleton_name}? This will also remove any child resources and can't be undone. + fields: &fields + id: + heading: Simple Singleton ID + absolutely_abstract_creative_concept_id: + heading: Creative Concept ID + name: + _: &name Name + label: *name + heading: *name + # 🚅 super scaffolding will insert new fields above this line. + created_at: + _: &created_at Added + label: *created_at + heading: *created_at + updated_at: + _: &updated_at Updated + label: *updated_at + heading: *updated_at + api: + collection_actions: "Collection Actions for Simple Singletons" + index: "List Simple Singletons" + create: "Add a New Simple Singleton" + member_actions: "Actions for an Individual Simple Singleton" + show: "Retrieve a Simple Singleton" + update: "Update a Simple Singleton" + destroy: "Delete a Simple Singleton" + fields: *fields + index: + section: "%{creative_concepts_possessive} Simple Singletons" + contexts: + scaffolding/absolutely_abstract/creative_concept: + header: Simple Singletons + description: Below is a list of Simple Singletons that have been added for %{creative_concept_name}. + description_empty: No Simple Singletons have been added for %{creative_concept_name}. + fields: *fields + buttons: *buttons + show: + section: "%{simple_singleton_name}" + header: Simple Singleton Details + description: Below are the details we have for %{simple_singleton_name}. + manage_description: You'll also find options for updating these details or removing %{simple_singleton_name} from %{creative_concept_name} entirely. + fields: *fields + buttons: *buttons + form: &form + buttons: *buttons + fields: *fields + new: + section: "New Simple Singleton for %{creative_concept_name}" + header: New Simple Singleton Details + description: Please provide the details of the new Simple Singleton you'd like to add to %{creative_concept_name}. + form: *form + edit: + section: "%{simple_singleton_name}" + header: Edit Simple Singleton Details + description: You can update the details or settings for %{simple_singleton_name} below. + form: *form + notifications: + created: Simple Singleton was successfully created. + updated: Simple Singleton was successfully updated. + destroyed: Simple Singleton was successfully destroyed. + account: + scaffolding: + completely_concrete: + simple_singletons: *simple_singletons + activerecord: + attributes: + scaffolding/completely_concrete/simple_singleton: + name: *name + # 🚅 super scaffolding will insert new activerecord attributes above this line. + created_at: *created_at + updated_at: *updated_at diff --git a/config/models/roles.yml b/config/models/roles.yml index 4584a2e9d..a1bfaf204 100644 --- a/config/models/roles.yml +++ b/config/models/roles.yml @@ -1,5 +1,6 @@ default: models: + Scaffolding::CompletelyConcrete::SimpleSingleton: read Team: read Membership: - read @@ -28,6 +29,7 @@ admin: - admin - editor models: + Scaffolding::CompletelyConcrete::SimpleSingleton: manage Team: manage Membership: manage Scaffolding::AbsolutelyAbstract::CreativeConcept: manage diff --git a/config/routes.rb b/config/routes.rb index ab4c7bb36..709663a60 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,7 +12,7 @@ # This helps mark `resources` definitions below as not actually defining the routes for a given resource, but just # making it possible for developers to extend definitions that are already defined by the `bullet_train` Ruby gem. # TODO Would love to get this out of the application routes file. - extending = {only: []} + extending = { only: [] } scope module: "public" do # To keep things organized, we put non-authenticated controllers in the `Public::` namespace. @@ -66,6 +66,20 @@ namespace :integrations do # 🚅 super scaffolding will insert new integration installations above this line. end + + namespace :scaffolding do + namespace :absolutely_abstract do + namespace :completely_concrete do + resources :simple_singletons + end + end + + # resources :absolutely_abstract_creative_concepts, path: 'absolutely_abstract/creative_concepts' do + # namespace :completely_concrete do + # resources :simple_singletons + # end + # end + end end end end diff --git a/config/routes/api/v1.rb b/config/routes/api/v1.rb index f20bc6a72..d604af285 100644 --- a/config/routes/api/v1.rb +++ b/config/routes/api/v1.rb @@ -30,6 +30,20 @@ namespace :integrations do # 🚅 super scaffolding will insert new integration installations above this line. end + + namespace :scaffolding do + namespace :absolutely_abstract do + namespace :completely_concrete do + resources :simple_singletons + end + end + + resources :absolutely_abstract_creative_concepts, path: 'absolutely_abstract/creative_concepts' do + namespace :completely_concrete do + resources :simple_singletons + end + end + end end end end diff --git a/db/migrate/20221215152529_create_scaffolding_completely_concrete_simple_singletons.rb b/db/migrate/20221215152529_create_scaffolding_completely_concrete_simple_singletons.rb new file mode 100644 index 000000000..a0654c741 --- /dev/null +++ b/db/migrate/20221215152529_create_scaffolding_completely_concrete_simple_singletons.rb @@ -0,0 +1,10 @@ +class CreateScaffoldingCompletelyConcreteSimpleSingletons < ActiveRecord::Migration[7.0] + def change + create_table :scaffolding_completely_concrete_simple_singletons do |t| + t.references :absolutely_abstract_creative_concept, null: false, foreign_key: {to_table: "scaffolding_absolutely_abstract_creative_concepts"}, index: {name: "index_simple_singletons_on_creative_concept_id"} + t.string :name + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 2f2ae4741..fb5bfeafc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_11_28_191001) do +ActiveRecord::Schema[7.0].define(version: 2022_12_15_152529) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -193,6 +193,14 @@ t.index ["membership_id"], name: "index_creative_concepts_collaborators_on_membership_id" end + create_table "scaffolding_completely_concrete_simple_singletons", force: :cascade do |t| + t.bigint "absolutely_abstract_creative_concept_id", null: false + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["absolutely_abstract_creative_concept_id"], name: "index_simple_singletons_on_creative_concept_id" + end + create_table "scaffolding_completely_concrete_tangible_things", force: :cascade do |t| t.bigint "absolutely_abstract_creative_concept_id", null: false t.string "text_field_value" @@ -353,6 +361,7 @@ add_foreign_key "scaffolding_absolutely_abstract_creative_concepts", "teams" add_foreign_key "scaffolding_absolutely_abstract_creative_concepts_collaborators", "memberships" add_foreign_key "scaffolding_absolutely_abstract_creative_concepts_collaborators", "scaffolding_absolutely_abstract_creative_concepts", column: "creative_concept_id" + add_foreign_key "scaffolding_completely_concrete_simple_singletons", "scaffolding_absolutely_abstract_creative_concepts", column: "absolutely_abstract_creative_concept_id" add_foreign_key "scaffolding_completely_concrete_tangible_things", "scaffolding_absolutely_abstract_creative_concepts", column: "absolutely_abstract_creative_concept_id" add_foreign_key "scaffolding_completely_concrete_tangible_things_assignments", "memberships" add_foreign_key "scaffolding_completely_concrete_tangible_things_assignments", "scaffolding_completely_concrete_tangible_things", column: "tangible_thing_id" diff --git a/test/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller_test.rb b/test/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller_test.rb new file mode 100644 index 000000000..e59ba7026 --- /dev/null +++ b/test/controllers/api/v1/scaffolding/completely_concrete/simple_singletons_controller_test.rb @@ -0,0 +1,115 @@ +require "controllers/api/v1/test" + +class Api::V1::Scaffolding::CompletelyConcrete::SimpleSingletonsControllerTest < Api::Test + def setup + # See `test/controllers/api/test.rb` for common set up for API tests. + super + + @absolutely_abstract_creative_concept = create(:scaffolding_absolutely_abstract_creative_concept, team: @team) +@simple_singleton = build(:scaffolding_completely_concrete_simple_singleton, absolutely_abstract_creative_concept: @absolutely_abstract_creative_concept) + @other_simple_singletons = create_list(:scaffolding_completely_concrete_simple_singleton, 3) + + @another_simple_singleton = create(:scaffolding_completely_concrete_simple_singleton, absolutely_abstract_creative_concept: @absolutely_abstract_creative_concept) + + # 🚅 super scaffolding will insert file-related logic above this line. + @simple_singleton.save + @another_simple_singleton.save + end + + # This assertion is written in such a way that new attributes won't cause the tests to start failing, but removing + # data we were previously providing to users _will_ break the test suite. + def assert_proper_object_serialization(simple_singleton_data) + # Fetch the simple_singleton in question and prepare to compare it's attributes. + simple_singleton = Scaffolding::CompletelyConcrete::SimpleSingleton.find(simple_singleton_data["id"]) + + assert_equal_or_nil simple_singleton_data['name'], simple_singleton.name + # 🚅 super scaffolding will insert new fields above this line. + + assert_equal simple_singleton_data["absolutely_abstract_creative_concept_id"], simple_singleton.absolutely_abstract_creative_concept_id + end + + test "index" do + # Fetch and ensure nothing is seriously broken. + get "/api/v1/scaffolding/absolutely_abstract/creative_concepts/#{@absolutely_abstract_creative_concept.id}/completely_concrete/simple_singletons", params: {access_token: access_token} + assert_response :success + + # Make sure it's returning our resources. + simple_singleton_ids_returned = response.parsed_body.map { |simple_singleton| simple_singleton["id"] } + assert_includes(simple_singleton_ids_returned, @simple_singleton.id) + + # But not returning other people's resources. + assert_not_includes(simple_singleton_ids_returned, @other_simple_singletons[0].id) + + # And that the object structure is correct. + assert_proper_object_serialization response.parsed_body.first + end + + test "show" do + # Fetch and ensure nothing is seriously broken. + get "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@simple_singleton.id}", params: {access_token: access_token} + assert_response :success + + # Ensure all the required data is returned properly. + assert_proper_object_serialization response.parsed_body + + # Also ensure we can't do that same action as another user. + get "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@simple_singleton.id}", params: {access_token: another_access_token} + assert_response :not_found + end + + test "create" do + # Use the serializer to generate a payload, but strip some attributes out. + params = {access_token: access_token} + simple_singleton_data = JSON.parse(build(:scaffolding_completely_concrete_simple_singleton, absolutely_abstract_creative_concept: nil).to_api_json) + simple_singleton_data.except!("id", "absolutely_abstract_creative_concept_id", "created_at", "updated_at") + params[:scaffolding_completely_concrete_simple_singleton] = simple_singleton_data + + post "/api/v1/scaffolding/absolutely_abstract/creative_concepts/#{@absolutely_abstract_creative_concept.id}/completely_concrete/simple_singletons", params: params + assert_response :success + + # # Ensure all the required data is returned properly. + assert_proper_object_serialization response.parsed_body + + # Also ensure we can't do that same action as another user. + post "/api/v1/scaffolding/absolutely_abstract/creative_concepts/#{@absolutely_abstract_creative_concept.id}/completely_concrete/simple_singletons", + params: params.merge({access_token: another_access_token}) + assert_response :not_found + end + + test "update" do + # Post an attribute update ensure nothing is seriously broken. + put "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@simple_singleton.id}", params: { + access_token: access_token, + scaffolding_completely_concrete_simple_singleton: { + name: 'Alternative String Value', + # 🚅 super scaffolding will also insert new fields above this line. + } + } + + assert_response :success + + # Ensure all the required data is returned properly. + assert_proper_object_serialization response.parsed_body + + # But we have to manually assert the value was properly updated. + @simple_singleton.reload + assert_equal @simple_singleton.name, 'Alternative String Value' + # 🚅 super scaffolding will additionally insert new fields above this line. + + # Also ensure we can't do that same action as another user. + put "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@simple_singleton.id}", params: {access_token: another_access_token} + assert_response :not_found + end + + test "destroy" do + # Delete and ensure it actually went away. + assert_difference("Scaffolding::CompletelyConcrete::SimpleSingleton.count", -1) do + delete "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@simple_singleton.id}", params: {access_token: access_token} + assert_response :success + end + + # Also ensure we can't do that same action as another user. + delete "/api/v1/scaffolding/completely_concrete/simple_singletons/#{@another_simple_singleton.id}", params: {access_token: another_access_token} + assert_response :not_found + end +end diff --git a/test/factories/scaffolding/completely_concrete/simple_singletons.rb b/test/factories/scaffolding/completely_concrete/simple_singletons.rb new file mode 100644 index 000000000..2bfa0ab0b --- /dev/null +++ b/test/factories/scaffolding/completely_concrete/simple_singletons.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :scaffolding_completely_concrete_simple_singleton, class: 'Scaffolding::CompletelyConcrete::SimpleSingleton' do + association :absolutely_abstract_creative_concept, factory: :scaffolding_absolutely_abstract_creative_concept + name { "MyString" } + end +end diff --git a/test/models/scaffolding/completely_concrete/simple_singleton_test.rb b/test/models/scaffolding/completely_concrete/simple_singleton_test.rb new file mode 100644 index 000000000..fac551d1d --- /dev/null +++ b/test/models/scaffolding/completely_concrete/simple_singleton_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class Scaffolding::CompletelyConcrete::SimpleSingletonTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end