Module: ActiveFields::CustomizableConcern
- Extended by:
- ActiveSupport::Concern
- Defined in:
- app/models/concerns/active_fields/customizable_concern.rb
Overview
Model mix-in that adds the active fields functionality to the customizable model
Instance Method Summary collapse
-
#active_fields ⇒ Object
Collection of active fields registered for this customizable.
-
#active_fields_attributes=(attributes) ⇒ Object
(also: #active_fields=)
Assigns the given attributes to the active_values association.
-
#active_fields_scope ⇒ Object
Scope value for the active fields collection.
-
#clear_unavailable_active_values ⇒ Object
Destroys all active_values that are no longer available for this customizable (e.g. after its scope has changed).
-
#initialize_active_values ⇒ Object
Build an active_value, if it doesn't exist, with a default value for each available active_field.
Instance Method Details
#active_fields ⇒ Object
Collection of active fields registered for this customizable.
117 118 119 |
# File 'app/models/concerns/active_fields/customizable_concern.rb', line 117 def active_fields self.class.active_fields(scope: active_fields_scope) end |
#active_fields_attributes=(attributes) ⇒ Object Also known as: active_fields=
Assigns the given attributes to the active_values association.
Accepts an Array of Hashes (symbol/string keys), a Hash of Hashes generated from HTTP/HTML parameters or permitted params. Each element should contain a :name key matching an existing active_field record. Element with a :value key will create an active_value if it doesn't exist or update an existing active_value, with the provided value. Element with a :_destroy key set to a truthy value will mark the matched active_value for destruction.
Example:
customizable.active_fields_attributes = [
{ name: "integer_array", value: [1, 4, 5, 5, 0] }, # create or update (symbol keys)
{ "name" => "text", "value" => "Lasso" }, # create or update (string keys)
{ name: "date", _destroy: true }, # destroy (symbol keys)
{ "name" => "boolean", "_destroy" => true }, # destroy (string keys)
permitted_params, # params could be passed, but they must be permitted
]
customizable.active_fields_attributes = {
"0" => { name: "integer_array", value: [1, 4, 5, 5, 0] }, # create or update (symbol keys)
"1" => { "name" => "text", "value" => "Lasso" }, # create or update (string keys)
"2" => { name: "date", _destroy: true }, # destroy (symbol keys)
"3" => { "name" => "boolean", "_destroy" => true }, # destroy (string keys)
}
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'app/models/concerns/active_fields/customizable_concern.rb', line 155 def active_fields_attributes=(attributes) attributes = attributes.to_h if attributes.respond_to?(:permitted?) unless attributes.is_a?(Array) || attributes.is_a?(Hash) raise ArgumentError, "Array or Hash expected for `active_fields=`, got #{attributes.class.name}" end # Handle `fields_for` params attributes = attributes.values if attributes.is_a?(Hash) active_fields_by_name = active_fields.index_by(&:name) active_values_by_field_id = active_values.index_by(&:active_field_id) nested_attributes = attributes.filter_map do |active_value_attributes| # Convert params to Hash active_value_attributes = active_value_attributes.to_h if active_value_attributes.respond_to?(:permitted?) active_value_attributes = active_value_attributes.with_indifferent_access active_field = active_fields_by_name[active_value_attributes[:name]] next if active_field.nil? active_value = active_values_by_field_id[active_field.id] if has_destroy_flag?(active_value_attributes) # Destroy { id: active_value&.id, _destroy: true } elsif active_value # Update { id: active_value.id, value: active_value_attributes[:value] } else # Create { active_field: active_field, value: active_value_attributes[:value] } end end self.active_values_attributes = nested_attributes end |
#active_fields_scope ⇒ Object
Scope value for the active fields collection.
122 123 124 125 126 |
# File 'app/models/concerns/active_fields/customizable_concern.rb', line 122 def active_fields_scope return if self.class.active_fields_scope_method.nil? send(self.class.active_fields_scope_method)&.to_s end |
#clear_unavailable_active_values ⇒ Object
Destroys all active_values that are no longer available for this customizable (e.g. after its scope has changed).
This method is suitable for customizables with scope functionality enabled
(when has_active_fields is called with a scope_method: parameter).
When a customizable's scope value changes,
some active_values may reference active_fields that are no longer available for the new scope.
This method identifies and destroys those orphaned active_values.
Example:
class User < ApplicationRecord
has_active_fields scope_method: :tenant_id
after_update :clear_unavailable_active_values, if: :saved_change_to_tenant_id?
end
225 226 227 228 229 230 231 |
# File 'app/models/concerns/active_fields/customizable_concern.rb', line 225 def clear_unavailable_active_values available_field_ids = active_fields.pluck(:id) active_values.select do |active_value| available_field_ids.exclude?(active_value.active_field_id) end.each(&:destroy) end |
#initialize_active_values ⇒ Object
Build an active_value, if it doesn't exist, with a default value for each available active_field. Returns active_values collection.
197 198 199 200 201 202 203 204 205 206 207 |
# File 'app/models/concerns/active_fields/customizable_concern.rb', line 197 def initialize_active_values existing_field_ids = active_values.map(&:active_field_id) active_fields.each do |active_field| next if existing_field_ids.include?(active_field.id) active_values.new(active_field: active_field, value: active_field.default_value) end active_values end |