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

Instance Method Details

#active_fieldsObject

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_scopeObject

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_valuesObject

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_valuesObject

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