Class: Binda::Choice
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Binda::Choice
- Defined in:
- app/models/binda/choice.rb
Overview
Choices are used in select, radio and checkboxes and defined by a **field setting**.
The architecture of this class is a bit complex and deserves some attention:
Here the rules that defines the class behaviour:
-
Choices must be associated to a **field setting**
-
Every choice can be associated to several select/radio/checkbox
-
(This is tricky) Assuming you are going to delete a choice and 1) **field setting** requires at least one choice
2) some **select/checkbox/radio** are associated just to that **choice**. To be able to do it you must first replace
that **choice** on those **select/checkbox/radio**. Only then you can delete that **choice**.
The **default choice** is applied only to field that requires at least a choice.
Instance Method Summary collapse
-
#assign_choice_to_selections(field_setting, new_default_choice) ⇒ Object
Assign a choice to ‘Binda::Selection` items belonging to a specific field setting.
-
#check_last_choice ⇒ Object
Some field setting requires at least one choice.
-
#reset_default_choice ⇒ Object
In order to make sure a default choice is set, this method is executed after the default choice is removed.
-
#set_default_choice ⇒ Object
In order to make sure that a default choice is set, this method is executed after the first choice is associated to the field setting.
Instance Method Details
#assign_choice_to_selections(field_setting, new_default_choice) ⇒ Object
Assign a choice to ‘Binda::Selection` items belonging to a specific field setting.
TODO it shouldn’t be possible to add another choice to a radio button.
The only reasonable way is to change has_many association in a has_one
69 70 71 72 73 74 75 76 |
# File 'app/models/binda/choice.rb', line 69 def assign_choice_to_selections(field_setting, new_default_choice) Selection.where(field_setting_id: field_setting.id).each do |selection| selection.choices << new_default_choice unless selection.save raise "It hasn't been possible to set the default choice for #{selection.class.name} with id=#{selection.id}." end end end |
#check_last_choice ⇒ Object
Some field setting requires at least one choice. To avoid leaving this kind of field setting without
any choice, a validation checks that there is at least an alternative choice that will become the default one.
This validation is skipped when deleting the field setting from which the choice depends because choice are
deleted directly from database (see `dependent: :delete_all`).
37 38 39 40 41 42 |
# File 'app/models/binda/choice.rb', line 37 def check_last_choice if !self.field_setting.allow_null? && Choice.where(field_setting_id: self.field_setting.id).length == 1 errors.add(:base, I18n.t('binda.choice.validation_message.destroy')) throw(:abort) end end |
#reset_default_choice ⇒ Object
In order to make sure a default choice is set, this method is executed after the
default choice is removed. What does it do? If the removed choice is the default one it sets
another defautl picking the first of the choices associated by id.
Once done, update all associated records that now don't have the any associated choice.
This method doesn’t run when a field setting is destroyed as the association is
`Binda::FieldSetting has_many :choices, dependent: :delete_all` not `dependent: :destory`.
That means the `after_destroy` callback for Binda::Choice (and this method as well) won't run.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'app/models/binda/choice.rb', line 86 def reset_default_choice # Make sure you are referring to the updated ActiveRecord object where the choice has already been deleted # Infact: self.field_setting != FieldSetting.find(self.field_setting.id) field_setting = FieldSetting.find(self.field_setting.id) # Don't do anything if the default choice isn't the one we just destroyed return if field_setting.choice_ids.include?(field_setting.default_choice_id) # Make sure the default choice is needed return if field_setting.allow_null? && field_setting.field_type != 'radio' if field_setting.choices.any? # Mark as default choice the first choice available update_default_choice(field_setting, field_setting.choices.first.id) else warn("WARNING: Binda::FieldSetting \"#{field_setting.slug}\" doesn't have any default choice! Please set a new default choice and then run the following command from Rails Console to update all related Binda::Selection records: \nrails binda:add_default_choice_to_all_selections_with_no_choices") # Remove default choice setting (which at this point is the current choice (self)) update_default_choice(field_setting, nil) end # Update all selection records which depend on the deleted choice Selection.check_all_selections_depending_on(field_setting) end |
#set_default_choice ⇒ Object
In order to make sure that a default choice is set, this method is executed after
the first choice is associated to the field setting. What does it do?
If there isn't a default it sets the current choice as the default one.
The method is executed as well if new choices are added.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'app/models/binda/choice.rb', line 48 def set_default_choice # Make sure you are referring to the updated ActiveRecord object where the choice has already been deleted # Infact: self.field_setting != FieldSetting.find( self.field_setting.id ) field_setting = FieldSetting.find(self.field_setting.id) if field_setting.default_choice_id.nil? && !field_setting.allow_null? # if field_setting.field_type = 'radio' field_setting.default_choice_id = self.id unless field_setting.save raise "It hasn't been possible to set the default choice for the current setting (#{field_setting.slug})." end assign_choice_to_selections(field_setting, self) end end |