active_fields 1.0.0 → 1.1.0
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +92 -77
- data/app/models/concerns/active_fields/customizable_concern.rb +4 -1
- data/lib/active_fields/engine.rb +6 -0
- data/lib/active_fields/version.rb +1 -1
- data/lib/active_fields.rb +51 -31
- data/lib/generators/active_fields/install/install_generator.rb +1 -1
- data/lib/generators/active_fields/scaffold/USAGE +9 -0
- data/lib/generators/active_fields/scaffold/scaffold_generator.rb +25 -0
- data/lib/generators/active_fields/scaffold/templates/controllers/active_fields_controller.rb +143 -0
- data/lib/generators/active_fields/scaffold/templates/helpers/active_fields_helper.rb +33 -0
- data/lib/generators/active_fields/scaffold/templates/javascript/controllers/array_field_controller.js +25 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/edit.html.erb +5 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb +53 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb +58 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb +63 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb +75 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb +63 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb +76 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb +61 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb +73 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb +58 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb +53 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/index.html.erb +41 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/new.html.erb +5 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/show.html.erb +29 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_boolean.html.erb +8 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_date.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_date_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_datetime.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_datetime_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_decimal.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_decimal_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_enum.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_enum_array.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_integer.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_integer_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_text.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_text_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/shared/_array_field.html.erb +19 -0
- metadata +39 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd75dc9f715c95766a238fd268c8174c7920e2b64ddce086f4bd7eed9ea2c36a
|
4
|
+
data.tar.gz: 74ba8eaf11a578067d0c45730a59aa60dc23363b9e5ffcce5bfca7795ee12da3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cc1b2984a7912497bc1b26cec3fc793bb897cc813c76440b5a8513834acae27d5c4df5da9c5f87cf9b36ae79351cacb52ab60965195fa6b44ce6ec8fc4f3c4e
|
7
|
+
data.tar.gz: 2f03d79bb28e91af86a99d36ff60a992b14ecf9c13d6d8a13eb92490790c4cd71afb11465173ba8a2a756cc24c3cf50c488a13bc8fca90d619b1079ec88fe216
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
## [Unreleased]
|
2
|
+
|
3
|
+
## [1.1.0] - 2024-09-10
|
4
|
+
- Added scaffold generator
|
5
|
+
- Disabled models reloading to prevent STI issues
|
6
|
+
|
7
|
+
## [1.0.0] - 2024-09-07
|
2
8
|
- Precision configuration for decimal fields
|
3
9
|
- Added array field types mix-in `ActiveFields::FieldArrayConcern`
|
4
10
|
- Fixed enum types behavior for blank values
|
data/README.md
CHANGED
@@ -9,9 +9,9 @@ enabling the addition of custom fields to any model at runtime without requiring
|
|
9
9
|
|
10
10
|
## Key Concepts
|
11
11
|
|
12
|
-
- **
|
13
|
-
- **Active
|
14
|
-
- **
|
12
|
+
- **Customizable**: A record that has custom fields (_Entity_).
|
13
|
+
- **Active Field**: A record with the definition of a custom field (_Attribute_).
|
14
|
+
- **Active Value**: A record that stores the value of an _Active Field_ for a specific _Customizable_ (_Value_).
|
15
15
|
|
16
16
|
## Models Structure
|
17
17
|
|
@@ -24,11 +24,11 @@ classDiagram
|
|
24
24
|
+ string name
|
25
25
|
+ string type
|
26
26
|
+ string customizable_type
|
27
|
-
+ json
|
27
|
+
+ json default_value_meta
|
28
28
|
+ json options
|
29
29
|
}
|
30
30
|
class ActiveValue {
|
31
|
-
+ json
|
31
|
+
+ json value_meta
|
32
32
|
}
|
33
33
|
class Customizable {
|
34
34
|
// This is your model
|
@@ -56,78 +56,90 @@ such as booleans, strings, numbers, arrays, etc.
|
|
56
56
|
3. Add the `has_active_fields` method to any models where you want to enable custom fields:
|
57
57
|
|
58
58
|
```ruby
|
59
|
-
class
|
59
|
+
class Post < ApplicationRecord
|
60
60
|
has_active_fields
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
-
4.
|
64
|
+
4. Run scaffold generator.
|
65
65
|
|
66
|
-
This plugin provides a convenient API
|
66
|
+
This plugin provides a convenient API, allowing you to write code that meets your specific needs
|
67
67
|
without being forced to use predefined implementations that is hard to extend.
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
69
|
+
However, for a quick start, you can generate a scaffold by running the following command:
|
70
|
+
|
71
|
+
```shell
|
72
|
+
bin/rails generate active_fields:scaffold
|
73
|
+
```
|
74
|
+
|
75
|
+
This command generates a controller, routes and views for managing _Active Fields_,
|
76
|
+
along with form inputs for _Active Values_ and some useful helper methods.
|
77
|
+
|
78
|
+
**Note:** Don't forget to add available _Customizable_ types in generated _Active Fields_ forms.
|
79
|
+
|
80
|
+
**Note:** The array field helper uses _Stimulus_ for interactivity.
|
81
|
+
If your app doesn't already include _Stimulus_, you can [easily add it](https://github.com/hotwired/stimulus-rails).
|
82
|
+
Alternatively, if you prefer not to use _Stimulus_, you should implement your own JavaScript code.
|
83
|
+
|
84
|
+
5. Add _Active Fields_ inputs in _Customizables_ forms and permit their params in controllers.
|
85
|
+
|
86
|
+
There are two methods available on _Customizable_ models for retrieving _Active Values_:
|
87
|
+
- `active_values` returns collection of only existing _Active Values_.
|
88
|
+
- `initialize_active_values` builds any missing _Active Values_ and returns the full collection.
|
89
|
+
|
90
|
+
Choose the method that suits your requirements.
|
91
|
+
In most cases, however, `initialize_active_values` is the more suitable option.
|
92
|
+
|
93
|
+
```erb
|
94
|
+
# app/views/posts/_form.html.erb
|
95
|
+
# ...
|
96
|
+
|
97
|
+
<%= form.fields_for :active_fields, post.initialize_active_values.sort_by(&:active_field_id), include_id: false do |active_fields_form| %>
|
98
|
+
<%= active_fields_form.hidden_field :name %>
|
99
|
+
<%= render_active_value_input(form: active_fields_form, active_value: active_fields_form.object) %>
|
100
|
+
<% end %>
|
101
|
+
|
102
|
+
# ...
|
103
|
+
```
|
104
|
+
|
105
|
+
Finally, permit the _Active Fields_ attributes in your _Customizables_ controllers:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# app/controllers/posts_controller.rb
|
109
|
+
# ...
|
110
|
+
|
111
|
+
def post_params
|
112
|
+
permitted_params = params.require(:post).permit(
|
113
|
+
# ...
|
114
|
+
active_fields_attributes: [:name, :value, :_destroy, value: []],
|
115
|
+
)
|
116
|
+
permitted_params[:active_fields_attributes]&.each do |_index, value_attrs|
|
117
|
+
value_attrs[:value] = compact_array_param(value_attrs[:value]) if value_attrs[:value].is_a?(Array)
|
118
|
+
end
|
119
|
+
|
120
|
+
permitted_params
|
121
|
+
end
|
122
|
+
|
123
|
+
# Removes an empty string from the beginning of the array parameter
|
124
|
+
def compact_array_param(value)
|
125
|
+
if value.first == ""
|
126
|
+
value[1..-1]
|
127
|
+
else
|
128
|
+
value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
**Note:** Here we use the `active_fields_attributes=` method (as a permitted parameter),
|
134
|
+
that integrates well with Rails `fields_for` to generate appropriate form fields.
|
135
|
+
Alternatively, the alias `active_fields=` can be used in contexts without `fields_for`, such as API controllers.
|
136
|
+
|
137
|
+
That's it!
|
138
|
+
You can now add _Active Fields_ to _Customizables_ at `http://localhost:3000/active_fields`
|
139
|
+
and fill in _Active Values_ within _Customizable_ forms.
|
140
|
+
|
141
|
+
You can also explore the [Demo app](https://github.com/lassoid/active_fields/blob/main/spec/dummy)
|
142
|
+
where the plugin is fully integrated into a full-stack Rails application.
|
131
143
|
Feel free to explore the source code and run it locally:
|
132
144
|
|
133
145
|
```shell
|
@@ -251,7 +263,7 @@ classDiagram
|
|
251
263
|
- `name`(`string`)
|
252
264
|
- `type`(`string`)
|
253
265
|
- `customizable_type`(`string`)
|
254
|
-
- `
|
266
|
+
- `default_value_meta` (`json`)
|
255
267
|
|
256
268
|
### Field Types Summary
|
257
269
|
|
@@ -495,6 +507,8 @@ For an example, refer to the [locale file](https://github.com/lassoid/active_fie
|
|
495
507
|
leading to the associated _Customizables_ also becoming invalid,
|
496
508
|
which could potentially result in update failures.
|
497
509
|
|
510
|
+
3. Only _Zeitwerk_ autoloading mode is supported.
|
511
|
+
|
498
512
|
## API Overview
|
499
513
|
|
500
514
|
### Fields API
|
@@ -510,7 +524,7 @@ active_field.type # Class name of this Active Field (utilizing STI)
|
|
510
524
|
active_field.customizable_type # Name of the Customizable model this Active Field is registered to
|
511
525
|
active_field.name # Identifier of this Active Field, it should be unique in scope of customizable_type
|
512
526
|
active_field.default_value_meta # JSON column declaring the default value. Consider using `default_value` instead
|
513
|
-
active_field.options #
|
527
|
+
active_field.options # JSON column containing type-specific attributes for this Active Field
|
514
528
|
|
515
529
|
# Methods:
|
516
530
|
active_field.default_value # Default value for all Active Values associated with this Active Field
|
@@ -523,7 +537,7 @@ active_field.customizable_model # Customizable model class
|
|
523
537
|
active_field.type_name # Identifier of the type of this Active Field (instead of class name)
|
524
538
|
|
525
539
|
# Scopes:
|
526
|
-
ActiveFields::Field::Boolean.for("
|
540
|
+
ActiveFields::Field::Boolean.for("Post") # Collection of Active Fields registered for the specified Customizable type
|
527
541
|
```
|
528
542
|
|
529
543
|
### Values API
|
@@ -546,7 +560,7 @@ active_value.name # Name of the associated Active Field
|
|
546
560
|
### Customizable API
|
547
561
|
|
548
562
|
```ruby
|
549
|
-
customizable =
|
563
|
+
customizable = Post.take
|
550
564
|
|
551
565
|
# Associations:
|
552
566
|
customizable.active_values # `has_many` association with Active Values linked to this Customizable
|
@@ -577,9 +591,10 @@ customizable.active_fields = [
|
|
577
591
|
# Please use `active_fields_attributes=`/`active_fields=` instead.
|
578
592
|
customizable.active_values_attributes = attributes
|
579
593
|
|
580
|
-
# Build
|
594
|
+
# Build not existing Active Values, with the default value for each Active Field.
|
595
|
+
# Returns full collection of Active Values.
|
581
596
|
# This method is useful with `fields_for`, allowing you to pass the collection as an argument to render new Active Values:
|
582
|
-
# `form.fields_for :
|
597
|
+
# `form.fields_for :active_fields, customizable.initialize_active_values`.
|
583
598
|
customizable.initialize_active_values
|
584
599
|
```
|
585
600
|
|
@@ -602,7 +617,7 @@ ActiveFields.config.register_field(:ip, "IpField") # Register a custom Active Fi
|
|
602
617
|
### Customizable Config
|
603
618
|
|
604
619
|
```ruby
|
605
|
-
customizable_model =
|
620
|
+
customizable_model = Post
|
606
621
|
customizable_model.active_fields_config # Access the Customizable's configuration
|
607
622
|
customizable_model.active_fields_config.customizable_model # The Customizable model itself
|
608
623
|
customizable_model.active_fields_config.types # Allowed Active Field types (e.g., `[:boolean]`)
|
@@ -80,7 +80,8 @@ module ActiveFields
|
|
80
80
|
|
81
81
|
alias_method :active_fields=, :active_fields_attributes=
|
82
82
|
|
83
|
-
# Build an active_value, if it doesn't exist, with a default value for each available active_field
|
83
|
+
# Build an active_value, if it doesn't exist, with a default value for each available active_field.
|
84
|
+
# Returns active_values collection.
|
84
85
|
def initialize_active_values
|
85
86
|
existing_field_ids = active_values.map(&:active_field_id)
|
86
87
|
|
@@ -89,6 +90,8 @@ module ActiveFields
|
|
89
90
|
|
90
91
|
active_values.new(active_field: active_field, value: active_field.default_value)
|
91
92
|
end
|
93
|
+
|
94
|
+
active_values
|
92
95
|
end
|
93
96
|
end
|
94
97
|
end
|
data/lib/active_fields/engine.rb
CHANGED
@@ -4,6 +4,12 @@ module ActiveFields
|
|
4
4
|
class Engine < ::Rails::Engine
|
5
5
|
isolate_namespace ActiveFields
|
6
6
|
|
7
|
+
config.eager_load_namespaces << ActiveFields
|
8
|
+
|
9
|
+
# Disable models reloading to avoid STI issues.
|
10
|
+
# Reloading can prevent subclasses from recognizing the base class.
|
11
|
+
config.autoload_once_paths = %W[#{root}/app/models #{root}/app/models/concerns]
|
12
|
+
|
7
13
|
initializer "active_fields.active_record" do
|
8
14
|
ActiveSupport.on_load(:active_record) do
|
9
15
|
include HasActiveFields
|
data/lib/active_fields.rb
CHANGED
@@ -4,42 +4,62 @@ require_relative "active_fields/version"
|
|
4
4
|
require_relative "active_fields/engine"
|
5
5
|
|
6
6
|
module ActiveFields
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
extend ActiveSupport::Autoload
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def eager_load!
|
11
|
+
super
|
12
|
+
Casters.eager_load!
|
13
|
+
Validators.eager_load!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
eager_autoload do
|
18
|
+
autoload :Config
|
19
|
+
autoload :CustomizableConfig
|
20
|
+
autoload :HasActiveFields
|
21
|
+
end
|
10
22
|
|
11
23
|
module Casters
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
extend ActiveSupport::Autoload
|
25
|
+
|
26
|
+
eager_autoload do
|
27
|
+
autoload :BaseCaster
|
28
|
+
autoload :BooleanCaster
|
29
|
+
autoload :DateCaster
|
30
|
+
autoload :DateArrayCaster
|
31
|
+
autoload :DateTimeCaster
|
32
|
+
autoload :DateTimeArrayCaster
|
33
|
+
autoload :DecimalCaster
|
34
|
+
autoload :DecimalArrayCaster
|
35
|
+
autoload :EnumCaster
|
36
|
+
autoload :EnumArrayCaster
|
37
|
+
autoload :IntegerCaster
|
38
|
+
autoload :IntegerArrayCaster
|
39
|
+
autoload :TextCaster
|
40
|
+
autoload :TextArrayCaster
|
41
|
+
end
|
26
42
|
end
|
27
43
|
|
28
44
|
module Validators
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
extend ActiveSupport::Autoload
|
46
|
+
|
47
|
+
eager_autoload do
|
48
|
+
autoload :BaseValidator
|
49
|
+
autoload :BooleanValidator
|
50
|
+
autoload :DateValidator
|
51
|
+
autoload :DateArrayValidator
|
52
|
+
autoload :DateTimeValidator
|
53
|
+
autoload :DateTimeArrayValidator
|
54
|
+
autoload :DecimalValidator
|
55
|
+
autoload :DecimalArrayValidator
|
56
|
+
autoload :EnumValidator
|
57
|
+
autoload :EnumArrayValidator
|
58
|
+
autoload :IntegerValidator
|
59
|
+
autoload :IntegerArrayValidator
|
60
|
+
autoload :TextValidator
|
61
|
+
autoload :TextArrayValidator
|
62
|
+
end
|
43
63
|
end
|
44
64
|
|
45
65
|
class << self
|
@@ -5,7 +5,7 @@ require "rails/generators"
|
|
5
5
|
module ActiveFields
|
6
6
|
module Generators
|
7
7
|
class InstallGenerator < ::Rails::Generators::Base
|
8
|
-
desc "This generator creates an
|
8
|
+
desc "This generator creates an initializer and copies plugin migrations"
|
9
9
|
|
10
10
|
def create_initializer
|
11
11
|
initializer "active_fields.rb", <<~RUBY
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Description:
|
2
|
+
Creates a controller, routes and views for managing Active Fields,
|
3
|
+
along with form inputs for Active Values and some useful helper methods.
|
4
|
+
|
5
|
+
The code it generates is unlikely to be a perfect fit for your application.
|
6
|
+
You’ll most probably want to customize the generated code.
|
7
|
+
|
8
|
+
Examples:
|
9
|
+
`bin/rails generate active_fields:scaffold`
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module ActiveFields
|
6
|
+
module Generators
|
7
|
+
class ScaffoldGenerator < ::Rails::Generators::Base
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
desc "This generator creates some useful templates"
|
11
|
+
|
12
|
+
def copy_files
|
13
|
+
Dir.glob("**/*", base: self.class.source_root).each do |path|
|
14
|
+
next unless File.file?(File.expand_path(path, self.class.source_root))
|
15
|
+
|
16
|
+
copy_file path, File.join("app", path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_routes
|
21
|
+
route "resources :active_fields"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveFieldsController < ApplicationController
|
4
|
+
helper ActiveFieldsHelper
|
5
|
+
|
6
|
+
before_action :set_active_field, only: %i[show edit update destroy]
|
7
|
+
|
8
|
+
def index
|
9
|
+
@active_fields = ActiveFields.config.field_base_class.order(:customizable_type, :id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def show; end
|
13
|
+
|
14
|
+
def new
|
15
|
+
@active_field = model_class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
@active_field = model_class.new(active_field_create_params(model_class))
|
20
|
+
|
21
|
+
if @active_field.save
|
22
|
+
redirect_to edit_active_field_path(@active_field), status: :see_other
|
23
|
+
else
|
24
|
+
render :new, status: :unprocessable_entity
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def edit; end
|
29
|
+
|
30
|
+
def update
|
31
|
+
if @active_field.update(active_field_update_params(@active_field.class))
|
32
|
+
redirect_to edit_active_field_path(@active_field), status: :see_other
|
33
|
+
else
|
34
|
+
render :edit, status: :unprocessable_entity
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy
|
39
|
+
@active_field.destroy!
|
40
|
+
|
41
|
+
redirect_to active_fields_path, status: :see_other
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def active_field_create_params(model_class)
|
47
|
+
params.require(:active_field).permit(*permitted_attributes_for_create(model_class)).tap do |attrs|
|
48
|
+
attrs.transform_values! do |value|
|
49
|
+
value.is_a?(Array) ? compact_array_param(value) : value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def active_field_update_params(model_class)
|
55
|
+
params.require(:active_field).permit(*permitted_attributes_for_update(model_class)).tap do |attrs|
|
56
|
+
attrs.transform_values! do |value|
|
57
|
+
value.is_a?(Array) ? compact_array_param(value) : value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def compact_array_param(value)
|
63
|
+
if value.first == ""
|
64
|
+
value[1..-1]
|
65
|
+
else
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# It is strongly recommended to move it to, for example, policies.
|
71
|
+
def permitted_attributes_for_create(model_class)
|
72
|
+
if model_class == ActiveFields::Field::Boolean
|
73
|
+
%i[customizable_type name required nullable default_value]
|
74
|
+
elsif model_class == ActiveFields::Field::Date
|
75
|
+
%i[customizable_type name required min max default_value]
|
76
|
+
elsif model_class == ActiveFields::Field::DateArray
|
77
|
+
[:customizable_type, :name, :min_size, :max_size, :min, :max, default_value: []]
|
78
|
+
elsif model_class == ActiveFields::Field::DateTime
|
79
|
+
%i[customizable_type name required min max precision default_value]
|
80
|
+
elsif model_class == ActiveFields::Field::DateTimeArray
|
81
|
+
[:customizable_type, :name, :min_size, :max_size, :min, :max, :precision, default_value: []]
|
82
|
+
elsif model_class == ActiveFields::Field::Decimal
|
83
|
+
%i[customizable_type name required min max precision default_value]
|
84
|
+
elsif model_class == ActiveFields::Field::DecimalArray
|
85
|
+
[:customizable_type, :name, :min_size, :max_size, :min, :max, :precision, default_value: []]
|
86
|
+
elsif model_class == ActiveFields::Field::Enum
|
87
|
+
[:customizable_type, :name, :required, :default_value, allowed_values: []]
|
88
|
+
elsif model_class == ActiveFields::Field::EnumArray
|
89
|
+
[:customizable_type, :name, :min_size, :max_size, allowed_values: [], default_value: []]
|
90
|
+
elsif model_class == ActiveFields::Field::Integer
|
91
|
+
%i[customizable_type name required min max default_value]
|
92
|
+
elsif model_class == ActiveFields::Field::IntegerArray
|
93
|
+
[:customizable_type, :name, :min_size, :max_size, :min, :max, default_value: []]
|
94
|
+
elsif model_class == ActiveFields::Field::Text
|
95
|
+
%i[customizable_type name min_length max_length default_value]
|
96
|
+
elsif model_class == ActiveFields::Field::TextArray
|
97
|
+
[:customizable_type, :name, :min_size, :max_size, :min_length, :max_length, default_value: []]
|
98
|
+
else
|
99
|
+
raise ArgumentError, "undefined model_class `#{model_class.inspect}`"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# It is strongly recommended to move it to, for example, policies.
|
104
|
+
def permitted_attributes_for_update(model_class)
|
105
|
+
if model_class == ActiveFields::Field::Boolean
|
106
|
+
%i[name default_value]
|
107
|
+
elsif model_class == ActiveFields::Field::Date
|
108
|
+
%i[name default_value]
|
109
|
+
elsif model_class == ActiveFields::Field::DateArray
|
110
|
+
[:name, default_value: []]
|
111
|
+
elsif model_class == ActiveFields::Field::DateTime
|
112
|
+
%i[name default_value]
|
113
|
+
elsif model_class == ActiveFields::Field::DateTimeArray
|
114
|
+
[:name, default_value: []]
|
115
|
+
elsif model_class == ActiveFields::Field::Decimal
|
116
|
+
%i[name default_value]
|
117
|
+
elsif model_class == ActiveFields::Field::DecimalArray
|
118
|
+
[:name, default_value: []]
|
119
|
+
elsif model_class == ActiveFields::Field::Enum
|
120
|
+
%i[name default_value]
|
121
|
+
elsif model_class == ActiveFields::Field::EnumArray
|
122
|
+
[:name, default_value: []]
|
123
|
+
elsif model_class == ActiveFields::Field::Integer
|
124
|
+
%i[name default_value]
|
125
|
+
elsif model_class == ActiveFields::Field::IntegerArray
|
126
|
+
[:name, default_value: []]
|
127
|
+
elsif model_class == ActiveFields::Field::Text
|
128
|
+
%i[name default_value]
|
129
|
+
elsif model_class == ActiveFields::Field::TextArray
|
130
|
+
[:name, default_value: []]
|
131
|
+
else
|
132
|
+
raise ArgumentError, "undefined model_class `#{model_class.inspect}`"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def set_active_field
|
137
|
+
@active_field = ActiveFields.config.field_base_class.find(params[:id])
|
138
|
+
end
|
139
|
+
|
140
|
+
def model_class
|
141
|
+
(ActiveFields.config.fields[params[:type]&.to_sym] || ActiveFields.config.type_class_names.first).constantize
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFieldsHelper
|
4
|
+
def render_array_field(form:, name:, value:, field_method:, field_opts: {})
|
5
|
+
render partial: "shared/array_field", locals: {
|
6
|
+
form: form,
|
7
|
+
name: name,
|
8
|
+
value: value,
|
9
|
+
field_method: field_method,
|
10
|
+
field_opts: field_opts,
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_active_field_form(active_field:)
|
15
|
+
partial = active_field_form(active_field)
|
16
|
+
|
17
|
+
render partial: partial, locals: { active_field: active_field }
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_active_value_input(form:, active_value:)
|
21
|
+
partial = active_value_input(active_value.active_field)
|
22
|
+
|
23
|
+
render partial: partial, locals: { form: form, active_value: active_value, active_field: active_value.active_field }
|
24
|
+
end
|
25
|
+
|
26
|
+
def active_field_form(active_field)
|
27
|
+
"active_fields/forms/#{active_field.type_name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def active_value_input(active_field)
|
31
|
+
"active_fields/values/inputs/#{active_field.type_name}"
|
32
|
+
end
|
33
|
+
end
|