From c46a0e1d2fcda5e7a9b520dff27d6b2fa9dd8268 Mon Sep 17 00:00:00 2001 From: Kirill Usanov <48535087+Exterm1nate@users.noreply.github.com> Date: Sat, 22 Feb 2025 13:34:22 +0300 Subject: [PATCH] Add registry to store relationships between Active Fields and Customizables (#20) --- CHANGELOG.md | 1 + README.md | 25 ++++++----- .../active_fields/customizable_concern.rb | 13 +++++- .../concerns/active_fields/field_concern.rb | 19 ++++++++- lib/active_fields.rb | 4 +- lib/active_fields/customizable_config.rb | 24 ----------- lib/active_fields/has_active_fields.rb | 7 ++-- lib/active_fields/registry.rb | 38 +++++++++++++++++ .../active_fields/forms/_boolean.html.erb | 2 +- .../views/active_fields/forms/_date.html.erb | 2 +- .../active_fields/forms/_date_array.html.erb | 2 +- .../active_fields/forms/_datetime.html.erb | 2 +- .../forms/_datetime_array.html.erb | 2 +- .../active_fields/forms/_decimal.html.erb | 2 +- .../forms/_decimal_array.html.erb | 2 +- .../views/active_fields/forms/_enum.html.erb | 2 +- .../active_fields/forms/_enum_array.html.erb | 2 +- .../active_fields/forms/_integer.html.erb | 2 +- .../forms/_integer_array.html.erb | 2 +- .../views/active_fields/forms/_text.html.erb | 2 +- .../active_fields/forms/_text_array.html.erb | 2 +- .../active_fields/forms/_boolean.html.erb | 2 +- .../views/active_fields/forms/_date.html.erb | 2 +- .../active_fields/forms/_date_array.html.erb | 2 +- .../active_fields/forms/_datetime.html.erb | 2 +- .../forms/_datetime_array.html.erb | 2 +- .../active_fields/forms/_decimal.html.erb | 2 +- .../forms/_decimal_array.html.erb | 2 +- .../views/active_fields/forms/_enum.html.erb | 2 +- .../active_fields/forms/_enum_array.html.erb | 2 +- .../active_fields/forms/_integer.html.erb | 2 +- .../forms/_integer_array.html.erb | 2 +- .../views/active_fields/forms/_ip.html.erb | 2 +- .../active_fields/forms/_ip_array.html.erb | 2 +- .../views/active_fields/forms/_text.html.erb | 2 +- .../active_fields/forms/_text_array.html.erb | 2 +- .../active_fields/customizable_config_spec.rb | 41 ------------------- spec/models/author_spec.rb | 18 ++++++-- spec/models/group_spec.rb | 6 --- spec/models/post_spec.rb | 18 ++++++-- spec/support/shared_examples/active_field.rb | 14 +++---- spec/support/test_methods.rb | 4 +- 42 files changed, 151 insertions(+), 137 deletions(-) delete mode 100644 lib/active_fields/customizable_config.rb create mode 100644 lib/active_fields/registry.rb delete mode 100644 spec/lib/active_fields/customizable_config_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d0c8b0..07e2cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Drop support for _Rails_ < 7.1 - Drop support for _Ruby_ < 3.1 (EOL) - Added search functionality +- Added registry to store relationships between _Customizable_ types and _Active Field_ types **Breaking changes**: - Maximum datetime precision reduced to 6 for all _Ruby_/_Rails_ versions. diff --git a/README.md b/README.md index e053af7..800b613 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Gem downloads count](https://img.shields.io/gem/dt/active_fields)](https://rubygems.org/gems/active_fields) [![Github Actions CI](https://github.com/lassoid/active_fields/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/lassoid/active_fields/actions/workflows/main.yml) -**ActiveFields** is a Rails plugin that implements the Entity-Attribute-Value (EAV) pattern, +**ActiveFields** is a _Rails_ plugin that implements the _Entity-Attribute-Value (EAV)_ pattern, enabling the addition of custom fields to any model at runtime without requiring changes to the database schema. ## Key Concepts @@ -75,8 +75,6 @@ such as booleans, strings, numbers, arrays, etc. This command generates a controller, routes, views for managing _Active Fields_, along with form inputs for _Active Values_, search form and some useful helper methods that will be used in next steps. - **Note:** Don't forget to add available _Customizable_ types in generated _Active Fields_ forms. - **Note:** The array field helper and search form use _Stimulus_ for interactivity. If your app doesn't already include _Stimulus_, you can [easily add it](https://github.com/hotwired/stimulus-rails). Alternatively, if you prefer not to use _Stimulus_, you should implement your own JavaScript code. @@ -122,7 +120,7 @@ such as booleans, strings, numbers, arrays, etc. ``` **Note:** Here we use the `active_fields_attributes=` method (as a permitted parameter), - that integrates well with Rails `fields_for` to generate appropriate form fields. + that integrates well with _Rails_ `fields_for` to generate appropriate form fields. Alternatively, the alias `active_fields=` can be used in contexts without `fields_for`, such as API controllers. **Note:** `compact_array_param` is a helper method, that was added by scaffold generator. @@ -157,7 +155,7 @@ fill in _Active Values_ within _Customizable_ forms and search _Customizables_ using their index actions. You can also explore the [Demo app](https://github.com/lassoid/active_fields/blob/main/spec/dummy) -where the plugin is fully integrated into a full-stack Rails application. +where the plugin is fully integrated into a full-stack _Rails_ application. Feel free to explore the source code and run it locally: ```shell @@ -819,13 +817,13 @@ Once defined, every _Active Value_ of this type will support the specified searc ```ruby # Find customizables Author.where_active_values([ - { name: "main_ip", operator: "=", value: "127.0.0.1" }, + { name: "main_ip", operator: "eq", value: "127.0.0.1" }, { n: "all_ips", op: "#>=", v: 5 }, { name: "all_ips", operator: "|=", value: "0.0.0.0" }, ]) # Find Active Values -IpFinder.new(active_field: ip_active_field).search(op: "=", value: "127.0.0.1") +IpFinder.new(active_field: ip_active_field).search(op: "eq", value: "127.0.0.1") IpArrayFinder.new(active_field: ip_array_active_field).search(op: "#>=", value: 5) ``` @@ -877,6 +875,7 @@ active_field.value_caster_class # Class used for values casting active_field.value_caster # Caster object that performs values casting active_field.customizable_model # Customizable model class active_field.type_name # Identifier of the type of this Active Field (instead of class name) +active_field.available_customizable_types # Available Customizable types for this Active Field # Scopes: ActiveFields::Field::Boolean.for("Post") # Collection of Active Fields registered for the specified Customizable type @@ -910,6 +909,8 @@ customizable.active_values # `has_many` association with Active Values linked to # Methods: customizable.active_fields # Collection of Active Fields registered for this record Post.active_fields # Collection of Active Fields registered for this model +Post.allowed_field_type_names # Active Fields type names allowed for this Customizable model +Post.allowed_field_class_names # Active Fields class names allowed for this Customizable model # Create, update or destroy Active Values. customizable.active_fields_attributes = [ @@ -966,14 +967,12 @@ ActiveFields.config.type_class_names # Registered Active Fields class names ActiveFields.config.register_field(:ip, "IpField") # Register a custom Active Field type ``` -### Customizable Config +### Registry ```ruby -customizable_model = Post -customizable_model.active_fields_config # Access the Customizable's configuration -customizable_model.active_fields_config.customizable_model # The Customizable model itself -customizable_model.active_fields_config.types # Allowed Active Field types (e.g., `[:boolean]`) -customizable_model.active_fields_config.types_class_names # Allowed Active Field class names (e.g., `[ActiveFields::Field::Boolean]`) +ActiveFields.registry.add(:boolean, "Post") # Stores relation between Active Field type and customizable type. Please do not use directly. +ActiveFields.registry.customizable_types_for(:boolean) # Returns Customizable types that allow provided Active Field type name +ActiveFields.registry.field_type_names_for("Post") # Returns Active Field type names, allowed for given Customizable type ``` ## Development diff --git a/app/models/concerns/active_fields/customizable_concern.rb b/app/models/concerns/active_fields/customizable_concern.rb index 47852cc..9d29876 100644 --- a/app/models/concerns/active_fields/customizable_concern.rb +++ b/app/models/concerns/active_fields/customizable_concern.rb @@ -81,8 +81,19 @@ module CustomizableConcern end class_methods do + # Collection of active fields registered for this customizable def active_fields - ActiveFields.config.field_base_class.for(model_name.name) + ActiveFields.config.field_base_class.for(name) + end + + # Returns field type names allowed for this customizable model. + def allowed_field_type_names + ActiveFields.registry.field_type_names_for(name).to_a + end + + # Returns field class names allowed for this customizable model. + def allowed_field_class_names + ActiveFields.config.fields.values_at(*allowed_field_type_names) end end diff --git a/app/models/concerns/active_fields/field_concern.rb b/app/models/concerns/active_fields/field_concern.rb index 9c6082f..cdb982c 100644 --- a/app/models/concerns/active_fields/field_concern.rb +++ b/app/models/concerns/active_fields/field_concern.rb @@ -89,6 +89,21 @@ def type_name ActiveFields.config.fields.key(type) end + # Returns customizable types that allow this field type. + # + # Notes: + # - The customizable model must be loaded to appear in this list. + # Relationships between customizable models and field types are established in the `has_active_fields` method, + # which is typically called within the customizable model. + # If eager loading is enabled, there should be no issues. + # However, if eager loading is disabled (common in development), + # the list will remain incomplete until all customizable models are loaded. + # - Code reloading may behave incorrectly at times. + # Restart your application if you make changes to the allowed types list in `has_active_fields`. + def available_customizable_types + ActiveFields.registry.customizable_types_for(type_name).to_a + end + private def validate_default_value @@ -107,8 +122,8 @@ def validate_default_value end def validate_customizable_model_allows_type - allowed_types = customizable_model&.active_fields_config&.types || [] - return true if allowed_types.include?(type_name) + allowed_type_names = ActiveFields.registry.field_type_names_for(customizable_type).to_a + return true if allowed_type_names.include?(type_name) errors.add(:customizable_type, :inclusion) false diff --git a/lib/active_fields.rb b/lib/active_fields.rb index 901f917..f336c6a 100644 --- a/lib/active_fields.rb +++ b/lib/active_fields.rb @@ -18,7 +18,7 @@ def eager_load! eager_autoload do autoload :Config - autoload :CustomizableConfig + autoload :Registry autoload :HasActiveFields end @@ -95,5 +95,7 @@ def config end alias_method :configure, :config + + def registry = Registry.instance end end diff --git a/lib/active_fields/customizable_config.rb b/lib/active_fields/customizable_config.rb deleted file mode 100644 index 7f2b92e..0000000 --- a/lib/active_fields/customizable_config.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -module ActiveFields - class CustomizableConfig - attr_reader :customizable_model, :types - - def initialize(customizable_model) - @customizable_model = customizable_model - end - - def types=(value) - invalid_types = value - ActiveFields.config.type_names - if invalid_types.any? - raise ArgumentError, "undefined ActiveFields types provided for #{customizable_model}: #{invalid_types}" - end - - @types = value - end - - def types_class_names - ActiveFields.config.fields.values_at(*types) - end - end -end diff --git a/lib/active_fields/has_active_fields.rb b/lib/active_fields/has_active_fields.rb index 4433ded..6e27589 100644 --- a/lib/active_fields/has_active_fields.rb +++ b/lib/active_fields/has_active_fields.rb @@ -6,13 +6,12 @@ module HasActiveFields extend ActiveSupport::Concern class_methods do - attr_reader :active_fields_config - def has_active_fields(types: ActiveFields.config.type_names) include CustomizableConcern - @active_fields_config = CustomizableConfig.new(self) - @active_fields_config.types = types + types.each do |field_type| + ActiveFields.registry.add(field_type, name) + end end end end diff --git a/lib/active_fields/registry.rb b/lib/active_fields/registry.rb new file mode 100644 index 0000000..ac11df8 --- /dev/null +++ b/lib/active_fields/registry.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module ActiveFields + # Storage for configured relations between active fields and customizable models + class Registry + include Singleton + + def initialize + @customizables = {} + @fields = {} + end + + # Add relation between active field type and customizable type + def add(field_type_name, customizable_type) + if ActiveFields.config.type_names.exclude?(field_type_name) + raise ArgumentError, "undefined ActiveFields type provided for #{customizable_type}: #{field_type_name}" + end + + @customizables[field_type_name] ||= Set.new + @customizables[field_type_name] << customizable_type + + @fields[customizable_type] ||= Set.new + @fields[customizable_type] << field_type_name + + nil + end + + # Returns customizable types that allow provided active field type name + def customizable_types_for(field_type_name) + @customizables[field_type_name] + end + + # Returns active field type names, allowed for given customizable type + def field_type_names_for(customizable_type) + @fields[customizable_type] + end + end +end diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb index 28c1620..b9a037f 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb index 6bde6df..3dfe252 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb index 86929b1..ecb24a9 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb index 7bc9229..7e52f63 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb index a7f2e5b..5854ecf 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb index 92f098c..188e782 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb index dce9214..6b0605f 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb index 4231800..5669827 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb index ab93963..0313892 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb index 0bf2c6d..7b153e5 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb index 4e64d37..d7bac16 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb index ba27a9b..009d861 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb index c4b722a..491e11b 100644 --- a/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb +++ b/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb @@ -24,7 +24,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, ["TODO: add allowed customizable model names"], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_boolean.html.erb b/spec/dummy/app/views/active_fields/forms/_boolean.html.erb index 6c1e711..6cba484 100644 --- a/spec/dummy/app/views/active_fields/forms/_boolean.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_boolean.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_date.html.erb b/spec/dummy/app/views/active_fields/forms/_date.html.erb index 32f3230..e2f7cb9 100644 --- a/spec/dummy/app/views/active_fields/forms/_date.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_date.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_date_array.html.erb b/spec/dummy/app/views/active_fields/forms/_date_array.html.erb index 6081be2..20510f8 100644 --- a/spec/dummy/app/views/active_fields/forms/_date_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_date_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_datetime.html.erb b/spec/dummy/app/views/active_fields/forms/_datetime.html.erb index 4f9ae82..3e26217 100644 --- a/spec/dummy/app/views/active_fields/forms/_datetime.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_datetime.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_datetime_array.html.erb b/spec/dummy/app/views/active_fields/forms/_datetime_array.html.erb index c6d7ddc..b52237e 100644 --- a/spec/dummy/app/views/active_fields/forms/_datetime_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_datetime_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_decimal.html.erb b/spec/dummy/app/views/active_fields/forms/_decimal.html.erb index 7fa561a..6f4ffe0 100644 --- a/spec/dummy/app/views/active_fields/forms/_decimal.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_decimal.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_decimal_array.html.erb b/spec/dummy/app/views/active_fields/forms/_decimal_array.html.erb index 6697f10..88e221a 100644 --- a/spec/dummy/app/views/active_fields/forms/_decimal_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_decimal_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_enum.html.erb b/spec/dummy/app/views/active_fields/forms/_enum.html.erb index f716d12..b38dee7 100644 --- a/spec/dummy/app/views/active_fields/forms/_enum.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_enum.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_enum_array.html.erb b/spec/dummy/app/views/active_fields/forms/_enum_array.html.erb index 0bb2fa8..aa1d03f 100644 --- a/spec/dummy/app/views/active_fields/forms/_enum_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_enum_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_integer.html.erb b/spec/dummy/app/views/active_fields/forms/_integer.html.erb index 8744086..ed4f35d 100644 --- a/spec/dummy/app/views/active_fields/forms/_integer.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_integer.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_integer_array.html.erb b/spec/dummy/app/views/active_fields/forms/_integer_array.html.erb index b509a61..274fc11 100644 --- a/spec/dummy/app/views/active_fields/forms/_integer_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_integer_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_ip.html.erb b/spec/dummy/app/views/active_fields/forms/_ip.html.erb index bbc8faf..8ba056c 100644 --- a/spec/dummy/app/views/active_fields/forms/_ip.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_ip.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_ip_array.html.erb b/spec/dummy/app/views/active_fields/forms/_ip_array.html.erb index 283a0d8..239eb8c 100644 --- a/spec/dummy/app/views/active_fields/forms/_ip_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_ip_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author Post], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_text.html.erb b/spec/dummy/app/views/active_fields/forms/_text.html.erb index e63874d..0a6178c 100644 --- a/spec/dummy/app/views/active_fields/forms/_text.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_text.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/dummy/app/views/active_fields/forms/_text_array.html.erb b/spec/dummy/app/views/active_fields/forms/_text_array.html.erb index 9023a6b..5be3293 100644 --- a/spec/dummy/app/views/active_fields/forms/_text_array.html.erb +++ b/spec/dummy/app/views/active_fields/forms/_text_array.html.erb @@ -14,7 +14,7 @@
<%= f.label :customizable_type %> - <%= f.select :customizable_type, %w[Author], {}, { disabled: active_field.persisted? } %> + <%= f.select :customizable_type, active_field.available_customizable_types, {}, { disabled: active_field.persisted? } %>
diff --git a/spec/lib/active_fields/customizable_config_spec.rb b/spec/lib/active_fields/customizable_config_spec.rb deleted file mode 100644 index 00d2c24..0000000 --- a/spec/lib/active_fields/customizable_config_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe ActiveFields::CustomizableConfig do - let(:object) { described_class.new(dummy_models.sample) } - - describe "types=" do - subject(:call_method) { object.types = value } - - context "with valid elements provided" do - let(:value) { ActiveFields.config.type_names.sample(rand(1..ActiveFields.config.type_names.size)) } - - it "sets types" do - call_method - - expect(object.types).to eq(value) - end - end - - context "with invalid elements provided" do - let(:value) { [ActiveFields.config.type_names.sample, :invalid] } - - it "raises an error" do - expect do - call_method - end.to raise_error(ArgumentError) - end - end - end - - describe "#types_class_names" do - subject(:call_method) { object.types_class_names } - - before do - object.types = ActiveFields.config.type_names.sample(rand(1..ActiveFields.config.type_names.size)) - end - - it "returns class names for configured types" do - expect(call_method).to eq(ActiveFields.config.fields.values_at(*object.types)) - end - end -end diff --git a/spec/models/author_spec.rb b/spec/models/author_spec.rb index 4c0b4e7..db3f12c 100644 --- a/spec/models/author_spec.rb +++ b/spec/models/author_spec.rb @@ -3,9 +3,21 @@ RSpec.describe Author do include_examples "customizable" - context "active_fields configuration" do - it "allows all types by default" do - expect(described_class.active_fields_config.types).to eq(ActiveFields.config.type_names) + context "methods" do + describe "##allowed_field_type_names" do + subject(:call_method) { described_class.allowed_field_type_names } + + it "contains all field types" do + expect(call_method).to eq(ActiveFields.config.type_names) + end + end + + describe "##allowed_field_class_names" do + subject(:call_method) { described_class.allowed_field_class_names } + + it "contains all field class names" do + expect(call_method).to eq(ActiveFields.config.type_class_names) + end end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index cfd1a04..73c5997 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -4,10 +4,4 @@ it "is not a customizable" do expect(described_class.ancestors).not_to include(ActiveFields::CustomizableConcern) end - - context "active_fields configuration" do - it "returns nil" do - expect(described_class.active_fields_config).to be_nil - end - end end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index b68b656..04a037b 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -3,9 +3,21 @@ RSpec.describe Post do include_examples "customizable" - context "active_fields configuration" do - it "allows only provided types" do - expect(described_class.active_fields_config.types).to eq(%i[boolean date_array decimal ip ip_array]) + context "methods" do + describe "##allowed_field_type_names" do + subject(:call_method) { described_class.allowed_field_type_names } + + it "contains only provided field types" do + expect(call_method).to eq(%i[boolean date_array decimal ip ip_array]) + end + end + + describe "##allowed_field_class_names" do + subject(:call_method) { described_class.allowed_field_class_names } + + it "contains only provided field class names" do + expect(call_method).to eq(ActiveFields.config.fields.values_at(*%i[boolean date_array decimal ip ip_array])) + end end end end diff --git a/spec/support/shared_examples/active_field.rb b/spec/support/shared_examples/active_field.rb index 489f50a..f989c9f 100644 --- a/spec/support/shared_examples/active_field.rb +++ b/spec/support/shared_examples/active_field.rb @@ -85,15 +85,12 @@ end describe "#validate_customizable_model_allows_type" do - let(:config) do - ActiveFields::CustomizableConfig.new(described_class).tap { _1.types = allowed_types } - end - context "when customizable_model allows this type" do let(:allowed_types) { [record.type_name] } before do - allow(record.customizable_model).to receive(:active_fields_config).and_return(config) + allow(ActiveFields.registry).to receive(:field_type_names_for).with(record.customizable_type) + .and_return(allowed_types) end it "is valid" do @@ -107,7 +104,8 @@ let(:allowed_types) { ActiveFields.config.type_names - [record.type_name] } before do - allow(record.customizable_model).to receive(:active_fields_config).and_return(config) + allow(ActiveFields.registry).to receive(:field_type_names_for).with(record.customizable_type) + .and_return(allowed_types) end it "is invalid" do @@ -118,10 +116,8 @@ end context "when customizable_model does not have active_fields" do - let(:config) { nil } - before do - allow(record.customizable_model).to receive(:active_fields_config).and_return(config) + allow(ActiveFields.registry).to receive(:field_type_names_for).with(record.customizable_type).and_return([]) end it "is invalid" do diff --git a/spec/support/test_methods.rb b/spec/support/test_methods.rb index 5082f3e..f831dd1 100644 --- a/spec/support/test_methods.rb +++ b/spec/support/test_methods.rb @@ -50,13 +50,13 @@ def dummy_models def customizable_models_for(active_field_class_name) dummy_models.select do |model| - model.active_fields_config.types_class_names.include?(active_field_class_name) + model.allowed_field_class_names.include?(active_field_class_name) end end def active_field_factories_for(customizable_model) active_field_factory_mappings.values_at( - *customizable_model.active_fields_config&.types_class_names, + *customizable_model.allowed_field_class_names, ) end