Class: Binda::FieldSetting

Inherits:
ApplicationRecord show all
Extended by:
FriendlyId
Defined in:
app/models/binda/field_setting.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_field_classesObject

An array of all classes which represent fields associated to Binda::FieldSetting This definition must stay on the top of the file



8
9
10
# File 'app/models/binda/field_setting.rb', line 8

def self.get_field_classes
  %w( String Text Date Image Video Repeater Radio Selection Checkbox Relation )
end

.get_id(field_slug) ⇒ integer

Retrieve the ID if a slug is provided and update the field_settings_array

in order to avoid calling the database (or the cached response) every time.
This should speed up requests and make Rails logs are cleaner.

Returns:

  • (integer)

    The ID of the field setting

Raises:

  • (ArgumentError)


191
192
193
194
195
196
197
198
199
# File 'app/models/binda/field_setting.rb', line 191

def self.get_id(field_slug)
  # Get field setting id from slug, without multiple calls to database 
  # (the query runs once and caches the result, then any further call uses the cached result)
  @@field_settings_array = self.pluck(:slug, :id) if @@field_settings_array.nil?
  selected_field_setting = @@field_settings_array.select{ |fs| fs[0] == field_slug }[0]
  raise ArgumentError, "There isn't any field setting with the current slug \"#{field_slug}\".", caller if selected_field_setting.nil?
  id = selected_field_setting[1]
  return id
end

.reset_field_settings_arraynull

Reset the field_settings_array. It’s called every time

the user creates or destroyes a Binda::FieldSetting

Returns:

  • (null)


205
206
207
208
209
210
# File 'app/models/binda/field_setting.rb', line 205

def self.reset_field_settings_array
  # Reset the result of the query taken with the above method,
  # this is needed when a user creates a new field_setting but 
  # `get_field_setting_id` has already run once
  @@field_settings_array = nil
end

Instance Method Details

#add_choice_if_allow_null_is_falseObject

Validation method that check if the current Binda::Selection instance has at least a choice before

updating allow null to false


293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'app/models/binda/field_setting.rb', line 293

def add_choice_if_allow_null_is_false
  if %(selection radio checkbox).include?(self.field_type) && 
    !self.allow_null?
    if self.choices.empty?
      # Add a choice if there is none, it will be automatically assign as default choice
      self.choices.create!(label: I18n.t("binda.choice.default_label"), value: I18n.t("binda.choice.default_value"))
    elsif self.default_choice_id.nil?
      # Assign a choice as default one if there is any
      # REVIEW there is some deprecation going on, but I'm not sure i directly involves the `update` method
      self.update!(default_choice_id: self.choices.first.id)
    end
  end
end

#check_allow_null_for_radioObject

It makes sure radio buttons have allow_null set to false.



175
176
177
178
179
180
# File 'app/models/binda/field_setting.rb', line 175

def check_allow_null_for_radio
  if field_type == 'radio' && allow_null?
    self.allow_null = false
    warn "WARNING: it's not possible that a field setting with type `radio` has allow_null=true."
  end
end

#check_allow_null_optionObject

Check allow_null option

Creating a selection with allow_null set to false will automatically generate a critical error.

This is due to the fact that 1) there is no choice to select, but 2) the selection field must have at least one.
The error can be easily removed by assigning a choice to the current field setting.

This method is preferred to a validation because it allows to remove all choices before adding new ones.



286
287
288
289
# File 'app/models/binda/field_setting.rb', line 286

def check_allow_null_option
    return if self.allow_null?
    Selection.check_all_selections_depending_on(self)
end

#convert_allow_null__nil_to_falseObject

Make sure that allow_null is set to false instead of nil.

(This isn't done with a database constraint in order to gain flexibility)

REVIEW: not sure what flexibility is needed. Maybe should be done differently



216
217
218
# File 'app/models/binda/field_setting.rb', line 216

def convert_allow_null__nil_to_false
  self.allow_null = false if self.allow_null.nil?
end

#create_field_instance_for(instance) ⇒ Object



259
260
261
262
263
264
265
266
267
# File 'app/models/binda/field_setting.rb', line 259

def create_field_instance_for(instance)
  if self.is_root?
    create_field_instances_for_instance(instance, field_class, self.id)
  else
    instance.repeaters.select{|r| r.field_setting_id == self.parent_id}.each do |repeater|
      create_field_instances_for_instance(repeater, field_class, self.id)
    end
  end
end

#create_field_instancesObject

Generates a default field instances for each existing component or board

which is associated to that field setting. This avoid having issues 
with Binda::FieldSetting.get_id method which would throw an ambiguous error 
saying that there isn't any field setting associated when infact it's 
the actual field missing, not the field setting itself.

A similar script runs after saving components and boards which makes sure

a field instance is always present no matter if the component has been created
before the field setting or the other way around.


249
250
251
252
253
254
255
256
257
# File 'app/models/binda/field_setting.rb', line 249

def create_field_instances
  # Get the structure
  structure = self.structures.includes(:board, components: [:repeaters]).first
  field_class = "Binda::#{self.field_type.classify}"
  structure.components.each do |component|
    create_field_instances_for_instance(component, field_class, self.id)
  end
  create_field_instances_for_instance(structure.board, field_class, self.id) if structure.board.present?
end

#create_field_instances_for_instance(instance, field_class, field_setting_id) ⇒ Object

Helper for create_field_instances method



270
271
272
273
274
275
276
# File 'app/models/binda/field_setting.rb', line 270

def create_field_instances_for_instance(instance, field_class, field_setting_id)
  field_class.constantize.find_or_create_by!(
    field_setting_id: field_setting_id,
    fieldable_id: instance.id,
    fieldable_type: instance.class.name
  )
end

#default_slugObject

Set slug name

It generates 4 possible slugs before falling back to FriendlyId default behaviour



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'app/models/binda/field_setting.rb', line 146

def default_slug
  slug = ''
  slug << self.field_group.structure.name
  slug << '-'
  slug << self.field_group.name
  unless self.parent.nil?
    slug << '-' 
    slug << self.parent.name 
  end
  return [ 
    "#{ slug }--#{ self.name }",
    "#{ slug }--#{ self.name }-1",
    "#{ slug }--#{ self.name }-2",
    "#{ slug }--#{ self.name }-3"
  ]
end

#is_rejected(attributes) ⇒ Object

Sets the validation rules to accept and save an attribute



66
67
68
# File 'app/models/binda/field_setting.rb', line 66

def is_rejected( attributes )
  attributes['label'].blank? || attributes['content'].blank?
end

#should_generate_new_friendly_id?Boolean

Friendly id preference on slug generation

Method inherited from friendly id



139
140
141
# File 'app/models/binda/field_setting.rb', line 139

def should_generate_new_friendly_id?
  slug.blank?
end

#slug_uniquenessObject

Check slug uniqueness



164
165
166
167
168
169
170
171
172
# File 'app/models/binda/field_setting.rb', line 164

def slug_uniqueness
  record_with_same_slug = self.class.where(slug: slug)
  if record_with_same_slug.any? && !record_with_same_slug.ids.include?(id)
    errors.add(:slug, I18n.t("binda.field_setting.validation_message.slug", { arg1: slug }))
    return false
  else
    return true 
  end
end

#structureActiveRecord

Get the structure of the field group to which the field setting belongs.

Returns:

  • (ActiveRecord)

    The Binda::Structure instance



236
237
238
# File 'app/models/binda/field_setting.rb', line 236

def structure
  self.structures.first
end

#structuresActiveRecord::Relation

Get structure on which the current field setting is attached. It should be one, but in order to

be able to add other methods to the query this methods returns a `ActiveRecord::Relation` object, not
a `ActiveRecord`

Returns:

  • (ActiveRecord::Relation)

    An array of Binda::Structure instances



225
226
227
228
229
230
231
# File 'app/models/binda/field_setting.rb', line 225

def structures
  Structure.left_outer_joins(
    field_groups: [:field_settings]
  ).where(
    binda_field_settings: { id: self.id }
  )
end