Class: Binda::Choice

Inherits:
ApplicationRecord show all
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:
  1. Choices must be associated to a **field setting**

  2. Every choice can be associated to several select/radio/checkbox

  3. (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

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

Parameters:



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_choiceObject

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_choiceObject

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_choiceObject

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