binda 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +42 -26
  3. data/Rakefile +4 -0
  4. data/app/assets/javascripts/binda/application.js +3 -0
  5. data/app/assets/javascripts/binda/components/field_setting_choices.js +5 -5
  6. data/app/assets/javascripts/binda/components/fileupload.js +1 -1
  7. data/app/assets/javascripts/binda/components/form_item_collapsable.js +245 -0
  8. data/app/assets/javascripts/binda/components/form_item_image.js +1 -1
  9. data/app/assets/javascripts/binda/components/login-shader.js +1 -1
  10. data/app/assets/javascripts/binda/components/login_form.js +1 -1
  11. data/app/assets/javascripts/binda/components/sortable.js +21 -30
  12. data/app/assets/javascripts/binda/dist/binda.bundle.js +299 -377
  13. data/app/assets/javascripts/binda/index.js +9 -17
  14. data/app/assets/stylesheets/binda/components/field_setting_choices.scss +5 -3
  15. data/app/assets/stylesheets/binda/components/form_item.scss +23 -70
  16. data/app/assets/stylesheets/binda/components/standard-form.scss +56 -1
  17. data/app/assets/stylesheets/binda/settings/tiny_mce_overrides.scss +8 -0
  18. data/app/controllers/binda/application_controller.rb +6 -0
  19. data/app/controllers/binda/boards_controller.rb +18 -12
  20. data/app/controllers/binda/components_controller.rb +21 -16
  21. data/app/controllers/binda/field_groups_controller.rb +57 -16
  22. data/app/controllers/binda/field_settings_controller.rb +14 -2
  23. data/app/controllers/binda/repeaters_controller.rb +2 -2
  24. data/app/controllers/binda/structures_controller.rb +32 -16
  25. data/app/controllers/concerns/binda/fieldable_helpers.rb +2 -2
  26. data/app/helpers/binda/components_helper.rb +16 -4
  27. data/app/helpers/binda/field_groups_helper.rb +4 -1
  28. data/app/models/binda/asset.rb +1 -3
  29. data/app/models/binda/component.rb +17 -10
  30. data/app/models/binda/date.rb +2 -6
  31. data/app/models/binda/field_group.rb +7 -5
  32. data/app/models/binda/field_setting.rb +69 -8
  33. data/app/models/binda/gallery.rb +2 -3
  34. data/app/models/binda/image.rb +7 -1
  35. data/app/models/binda/relation.rb +2 -5
  36. data/app/models/binda/repeater.rb +10 -14
  37. data/app/models/binda/selection.rb +3 -3
  38. data/app/models/binda/structure.rb +9 -5
  39. data/app/models/binda/text.rb +2 -6
  40. data/app/models/binda/user.rb +10 -0
  41. data/app/models/concerns/binda/field_uniqueness.rb +31 -0
  42. data/app/models/concerns/binda/fieldable_association_helpers.rb +31 -11
  43. data/app/models/concerns/binda/fieldable_associations.rb +2 -3
  44. data/app/models/concerns/binda/fields.rb +21 -0
  45. data/app/views/binda/boards/edit.html.erb +2 -1
  46. data/app/views/binda/components/edit.html.erb +2 -1
  47. data/app/views/binda/field_groups/_form_body.html.erb +4 -42
  48. data/app/views/binda/field_groups/_form_header.html.erb +11 -0
  49. data/app/views/binda/field_groups/_form_item.html.erb +4 -6
  50. data/app/views/binda/field_groups/_form_new_item.html.erb +8 -0
  51. data/app/views/binda/field_groups/_form_section.html.erb +17 -27
  52. data/app/views/binda/field_groups/_form_section_repeater.html.erb +17 -18
  53. data/app/views/binda/field_groups/_form_sidebar.html.erb +13 -0
  54. data/app/views/binda/field_groups/form_item/_form_item_editor.html.erb +9 -5
  55. data/app/views/binda/field_groups/form_item/{_form_item_persisted_editor.html.erb → _form_item_editor_existing_item.html.erb} +1 -4
  56. data/app/views/binda/field_groups/form_item/_form_item_editor_new_item.html.erb +3 -0
  57. data/app/views/binda/field_groups/form_item/_form_item_header.html.erb +23 -24
  58. data/app/views/binda/field_groups/form_section/_form_section_header.html.erb +45 -0
  59. data/app/views/binda/field_groups/form_section/_form_section_list.html.erb +9 -0
  60. data/app/views/binda/fieldable/_form_body.html.erb +6 -1
  61. data/app/views/binda/fieldable/_form_item_date.html.erb +1 -1
  62. data/app/views/binda/fieldable/_form_item_image.html.erb +1 -1
  63. data/app/views/binda/fieldable/_form_item_new_repeater.html.erb +7 -21
  64. data/app/views/binda/fieldable/_form_item_relation.html.erb +7 -7
  65. data/app/views/binda/fieldable/_form_item_repeater.html.erb +9 -99
  66. data/app/views/binda/fieldable/_form_item_selections.html.erb +1 -1
  67. data/app/views/binda/fieldable/_form_item_string.html.erb +5 -12
  68. data/app/views/binda/fieldable/_form_item_text.html.erb +5 -13
  69. data/app/views/binda/fieldable/_form_item_video.html.erb +1 -1
  70. data/app/views/binda/fieldable/_form_section.html.erb +11 -10
  71. data/app/views/binda/fieldable/_form_section_repeater.html.erb +2 -3
  72. data/app/views/binda/fieldable/form_item_repeater/_form_item_repeater_header.html.erb +32 -0
  73. data/app/views/binda/fieldable/form_item_repeater/_form_item_repeater_list.html.erb +19 -0
  74. data/app/views/binda/fieldable/form_item_repeater/_form_item_repeater_list_item.html.erb +42 -0
  75. data/app/views/binda/structures/_form_field_group_item.html.erb +5 -0
  76. data/app/views/binda/structures/_form_new_field_group_item.html.erb +8 -0
  77. data/app/views/binda/structures/_form_section.html.erb +16 -78
  78. data/app/views/binda/structures/_form_sidebar.html.erb +9 -8
  79. data/app/views/binda/structures/form_field_group_item/_form_field_group_item_editor.html.erb +18 -0
  80. data/app/views/binda/structures/form_field_group_item/_form_field_group_item_field_setting_form.html.erb +12 -0
  81. data/app/views/binda/structures/form_field_group_item/_form_field_group_item_field_settings.html.erb +18 -0
  82. data/app/views/binda/structures/form_field_group_item/_form_field_group_item_header.html.erb +29 -0
  83. data/app/views/binda/structures/form_section/_form_section_header.html.erb +26 -0
  84. data/app/views/binda/structures/form_section/_form_section_list.html.erb +8 -0
  85. data/config/initializers/simple_form__fileupload.rb +3 -4
  86. data/config/locales/en.yml +9 -4
  87. data/config/routes.rb +4 -0
  88. data/lib/binda/version.rb +1 -1
  89. data/lib/generators/binda/install/install_generator.rb +17 -6
  90. data/lib/generators/binda/maintenance/maintenance_generator.rb +12 -8
  91. data/lib/generators/binda/setup/setup_generator.rb +23 -27
  92. data/lib/tasks/create_missing_field_instances_task.rake +10 -0
  93. data/lib/tasks/remove_orphan_fields_task.rake +1 -7
  94. data/lib/tasks/user_tasks.rake +1 -7
  95. data/vendor/assets/javascripts/lodash.js +17097 -0
  96. metadata +39 -7
  97. data/app/assets/javascripts/binda/components/form_item.js +0 -113
  98. data/app/assets/javascripts/binda/components/form_item_editor.js +0 -39
  99. data/app/assets/javascripts/binda/components/form_item_repeater.js +0 -127
  100. data/app/views/binda/field_groups/form_item/_form_item_new_editor.html.erb +0 -8
@@ -3,7 +3,7 @@ require_dependency "binda/application_controller"
3
3
  module Binda
4
4
  class FieldGroupsController < ApplicationController
5
5
  before_action :set_structure
6
- before_action :set_field_group, only: [:show, :edit, :update, :destroy]
6
+ before_action :set_field_group, only: [:show, :edit, :update, :destroy, :add_field_setting]
7
7
 
8
8
  def index
9
9
  redirect_to structure_field_group_path( @structure.slug )
@@ -33,7 +33,6 @@ module Binda
33
33
 
34
34
  def update
35
35
  # Add nested classes
36
- add_new_field_settings
37
36
  add_new_choices
38
37
  check_if_needs_to_update_choices
39
38
 
@@ -47,9 +46,39 @@ module Binda
47
46
  end
48
47
 
49
48
  def destroy
50
- @field_group.destroy
49
+ @field_group.destroy!
51
50
  reset_field_settings_cache
52
- redirect_to structure_path( @structure.slug ), notice: 'Field group was successfully destroyed.'
51
+ if params[:isAjax]
52
+ render json: { target_id: params[:target_id] }, status: 200
53
+ else
54
+ redirect_to structure_path( @structure.slug ), notice: 'Field group was successfully destroyed along with all dependents.'
55
+ end
56
+ end
57
+
58
+ def sort
59
+ params[:field_group].each_with_index do |id, i|
60
+ FieldGroup.find( id ).update_column('position', i+1) # use update_column to skip callbacks (which leads to huge useless memory consumption)
61
+ end
62
+ render json: { id: "##{params[:id]}" }, status: 200
63
+ end
64
+
65
+ def sort_field_settings
66
+ sort_field_setting_by(params["form--list-item"])
67
+ render json: { id: "##{params[:id]}" }, status: 200
68
+ end
69
+
70
+ def add_field_setting
71
+ # We set some default values in order to be able to save the field setting
72
+ # (if field setting isn't save it makes impossible to sort the order)
73
+ # TODO params should be passed into a permit method
74
+ @field_setting = FieldSetting.new(
75
+ name: "#{I18n.t('binda.field_setting.new')}",
76
+ field_group_id: @field_group.id,
77
+ field_type: 'string',
78
+ ancestry: params[:ancestry]
79
+ )
80
+ @field_setting.save!
81
+ render 'binda/field_groups/_form_new_item', layout: false
53
82
  end
54
83
 
55
84
  private
@@ -64,27 +93,30 @@ module Binda
64
93
 
65
94
  # Only allow a trusted parameter "white list" through.
66
95
  def field_group_params
67
- params.require(:field_group).permit(:name, :slug, :description, :position, :layout, :structure_id, field_settings_attributes: [ :id, :field_group_id, :field_setting_id, :name, :slug, :description, :field_type, :position, :required, :default_text, :ancestry, :default_choice_id, :allow_null, accepted_structure_ids: [], choices: [], choices_attributes: [ :id, :field_setting_id, :label, :value ]])
96
+ params.require(:field_group).permit(
97
+ :name, :slug, :description, :position, :layout, :structure_id, field_settings_attributes: [
98
+ :id, :field_group_id, :field_setting_id, :name, :slug, :description, :field_type, :position, :required, :default_text, :ancestry, :default_choice_id, :allow_null, accepted_structure_ids: [], choices: [], choices_attributes: [
99
+ :id, :field_setting_id, :label, :value
100
+ ]
101
+ ]
102
+ )
68
103
  end
69
104
 
70
105
  def new_params
71
- params.require(:field_group).permit( new_field_settings: [ :id, :field_group_id, :field_setting_id, :name, :slug, :description, :field_type, :position, :required, :ancestry, :default_choice_id, :allow_null, choices: [] ],new_choices: [ :id, :field_setting_id, :label, :value ])
106
+ params.require(:field_group).permit(
107
+ new_field_settings: [
108
+ :id, :field_group_id, :field_setting_id, :name, :slug, :description, :field_type, :position, :required, :ancestry, :default_choice_id, :allow_null, choices: []
109
+ ],
110
+ new_choices: [
111
+ :id, :field_setting_id, :label, :value
112
+ ]
113
+ )
72
114
  end
73
115
 
74
116
  def reset_field_settings_cache
75
117
  FieldSetting.reset_field_settings_array
76
118
  end
77
119
 
78
- def add_new_field_settings
79
- # Create new fields if any
80
- new_params[:new_field_settings].each do |field_setting|
81
- next if field_setting[:name].blank?
82
- new_field_setting = @field_group.field_settings.create( field_setting )
83
- next if new_field_setting
84
- return redirect_to edit_structure_field_group_path( @structure.slug, @field_group.slug ), flash: { error: new_field_setting.errors }
85
- end
86
- end
87
-
88
120
  def add_new_choices
89
121
  # Create new fields if any
90
122
  return if new_params[:new_choices].nil?
@@ -118,5 +150,14 @@ module Binda
118
150
  end
119
151
  end
120
152
  end
153
+
154
+ # Sort field settings following the order with which are listed in the array provided as a argument.
155
+ #
156
+ # @param field_settings [Array] the list of ids of the field settings
157
+ def sort_field_setting_by(field_settings)
158
+ field_settings.each_with_index do |id, i|
159
+ FieldSetting.find( id ).update_column('position', i+1)
160
+ end
161
+ end
121
162
  end
122
163
  end
@@ -40,8 +40,20 @@ module Binda
40
40
  end
41
41
 
42
42
  def destroy
43
- @field_setting.destroy
44
- redirect_to structure_field_group_path( @structure, @field_group ), notice: 'Field setting and all dependent content were successfully destroyed.'
43
+ @field_setting.destroy!
44
+ FieldSetting.reset_field_settings_array
45
+ if params[:isAjax]
46
+ render json: { target_id: params[:target_id] }, status: 200
47
+ else
48
+ redirect_to structure_field_group_path( @structure, @field_group ), notice: 'Field setting and all dependent content were successfully destroyed.'
49
+ end
50
+ end
51
+
52
+ def sort
53
+ params[:field_setting].each_with_index do |id, i|
54
+ FieldSetting.find( id ).update_column('position', i+1) # use update_column to skip callbacks (which leads to huge useless memory consumption)
55
+ end
56
+ render json: { id: "##{params[:id]}" }, status: 200
45
57
  end
46
58
 
47
59
  private
@@ -35,10 +35,10 @@ module Binda
35
35
 
36
36
  # DELETE /repeaters/1
37
37
  def destroy
38
- @repeater.destroy
38
+ @repeater.destroy!
39
39
  # redirect_to repeaters_url, notice: 'Repeater was successfully destroyed.'
40
40
  if params['isAjax']
41
- head :ok
41
+ render json: { target_id: params[:target_id] }, status: 200
42
42
  else
43
43
  redirect_to :back, notice: 'Field group was successfully destroyed.'
44
44
  end
@@ -2,7 +2,7 @@ require_dependency "binda/application_controller"
2
2
 
3
3
  module Binda
4
4
  class StructuresController < ApplicationController
5
- before_action :set_structure, only: [:show, :edit, :update, :destroy, :fields_update ]
5
+ before_action :set_structure, only: [:show, :edit, :update, :destroy, :fields_update, :add_field_group ]
6
6
 
7
7
  def index
8
8
  @structures = Structure.order('position').all.page params[:page]
@@ -30,9 +30,6 @@ module Binda
30
30
  end
31
31
 
32
32
  def update
33
- # Create new fields if any
34
- add_new_field_groups
35
-
36
33
  # Update the other ones
37
34
  if @structure.update(structure_params)
38
35
  redirect_to structure_path( @structure.slug ), notice: "#{ @structure.name.capitalize } structure was successfully updated."
@@ -52,7 +49,7 @@ module Binda
52
49
 
53
50
  def sort
54
51
  params[:structure].each_with_index do |id, i|
55
- Structure.find( id ).update({ position: i + 1 })
52
+ Structure.find( id ).update({ position: i })
56
53
  end
57
54
  render js: "$('##{params[:id]}').sortable('option', 'disabled', false); $('.popup-warning').addClass('popup-warning--hidden'); $('.sortable').removeClass('sortable--disabled')"
58
55
  end
@@ -61,6 +58,22 @@ module Binda
61
58
  @structures = Structure.order('position').all.page params[:page]
62
59
  end
63
60
 
61
+ def sort_field_groups
62
+ sort_field_group_by(params["form--list-item"])
63
+ render json: { id: "##{params[:id]}" }, status: 200
64
+ end
65
+
66
+ def add_field_group
67
+ # We set some default values in order to be able to save the field setting
68
+ # (if field setting isn't save it makes impossible to sort the order)
69
+ @field_group = FieldGroup.new(
70
+ name: "#{I18n.t('binda.field_group.new')}",
71
+ structure_id: @structure.id
72
+ )
73
+ @field_group.save!
74
+ render 'binda/structures/_form_new_field_group_item', layout: false
75
+ end
76
+
64
77
  private
65
78
  # Use callbacks to share common setup or constraints between actions.
66
79
  def set_structure
@@ -69,24 +82,27 @@ module Binda
69
82
 
70
83
  # Only allow a trusted parameter "white list" through.
71
84
  def structure_params
72
- params.require(:structure).permit(:name, :slug, :position, :has_categories, :has_preview, :instance_type, field_groups_attributes: [ :id, :name, :structure_id, :slug ] )
85
+ params.require(:structure).permit(
86
+ :name, :slug, :position, :has_categories, :has_preview, :instance_type, field_groups_attributes: [
87
+ :id, :name, :structure_id, :slug, :description, field_settings_attributes: [
88
+ :id, :name, :slug, :field_group_id
89
+ ]
90
+ ]
91
+ )
73
92
  end
74
93
 
75
94
  def new_params
76
95
  params.require(:structure).permit( new_field_groups:[ :name, :slug, :structure_id ] )
77
96
  end
78
97
 
79
- def add_new_field_groups
80
- new_params[:new_field_groups].each do |field_group|
81
- next if field_group[:name].blank?
82
- new_field_group = @structure.field_groups.create(name: field_group[:name], slug: field_group[:slug])
83
- unless new_field_group
84
- return redirect_to(
85
- structure_path(@structure.slug),
86
- flash: { error: new_field_group.errors }
87
- )
88
- end
98
+ # Sort field settings following the order with which are listed in the array provided as a argument.
99
+ #
100
+ # @param field_settings [Array] the list of ids of the field settings
101
+ def sort_field_group_by(field_groups)
102
+ field_groups.each_with_index do |id, i|
103
+ FieldGroup.find( id ).update_column('position', i+1)
89
104
  end
90
105
  end
106
+
91
107
  end
92
108
  end
@@ -14,7 +14,7 @@ module Binda
14
14
  radios_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :choice_ids ],
15
15
  selections_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :choice_ids ],
16
16
  checkboxes_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, choice_ids: [] ],
17
- relations_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, dependent_component_ids: [], parent_related_board_ids: [] ],
17
+ relations_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, dependent_component_ids: [], dependent_board_ids: [] ],
18
18
  repeaters_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :field_group_id,
19
19
  texts_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :content ],
20
20
  strings_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :content ],
@@ -22,7 +22,7 @@ module Binda
22
22
  videos_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :video, :video_cache ],
23
23
  dates_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :date ],
24
24
  galleries_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id ],
25
- relations_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, dependent_component_ids: [], parent_related_board_ids: [] ],
25
+ relations_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, dependent_component_ids: [], dependent_board_ids: [] ],
26
26
  repeaters_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :field_group_id ],
27
27
  radios_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :choice_ids ],
28
28
  selections_attributes: [ :id, :field_setting_id, :fieldable_type, :fieldable_id, :choice_ids ],
@@ -36,16 +36,28 @@ module Binda
36
36
  #
37
37
  # @param field_setting [Binda::FieldSetting] The field setting object
38
38
  def prepare_description_for_selections_form_hint(field_setting)
39
- description = []
40
39
  unless field_setting.description.blank? && field_setting.allow_null?
41
- description << field_setting.description unless field_setting.description.blank?
42
- description << I18n.t("binda.null_is_not_allowed") if !field_setting.allow_null?
43
- return description.join('. ')
40
+ prepare_description_for_selections_from_hint_with(field_setting)
44
41
  else
45
42
  return false
46
43
  end
47
44
  end
48
45
 
46
+ #
47
+ # Prepare description for selections with field setting detail
48
+ #
49
+ # @param field_setting The field setting
50
+ #
51
+ # @return [String] The description
52
+ #
53
+ def prepare_description_for_selections_from_hint_with(field_setting)
54
+ description = []
55
+ description << field_setting.description unless field_setting.description.blank?
56
+ description << I18n.t("binda.null_is_not_allowed") if !field_setting.allow_null?
57
+ return description.join('. ')
58
+ end
59
+
60
+
49
61
  # Get sort link by argument
50
62
  #
51
63
  # This method returns a URL which contains the current sort options
@@ -1,12 +1,13 @@
1
1
  module Binda
2
2
  module FieldGroupsHelper
3
3
 
4
-
4
+ # Returns the right path for "new" or "edit" action
5
5
  def get_form_field_group_url
6
6
  return structure_field_groups_path if action_name == 'new'
7
7
  return structure_field_group_path if action_name == 'edit'
8
8
  end
9
9
 
10
+ # Get all components related to a "relation" field setting
10
11
  def get_relationable_components(field_setting)
11
12
  if @instance.class.to_s == 'Binda::Component'
12
13
  Binda::Component.where(structure_id: Binda::Structure.where(id: field_setting.accepted_structure_ids)).where.not(id: @instance.id)
@@ -15,6 +16,7 @@ module Binda
15
16
  end
16
17
  end
17
18
 
19
+ # Get all boards related to a "relation" field setting
18
20
  def get_relationable_boards(field_setting)
19
21
  if @instance.class.to_s == 'Binda::Component'
20
22
  Binda::Board.where(structure_id: Binda::Structure.where(id: field_setting.accepted_structure_ids))
@@ -23,6 +25,7 @@ module Binda
23
25
  end
24
26
  end
25
27
 
28
+ # Retrieve the number of records present in the database for the current structure
26
29
  def get_entries_number
27
30
  instance_type = @structure.instance_type
28
31
  if ['board', 'component'].include? instance_type
@@ -3,9 +3,7 @@ module Binda
3
3
  # all the classes that deal with files.
4
4
  class Asset < ApplicationRecord
5
5
 
6
- # Associations
7
- belongs_to :fieldable, polymorphic: true
8
- belongs_to :field_setting
6
+ include Fields
9
7
 
10
8
  end
11
9
  end
@@ -15,7 +15,8 @@ module Binda
15
15
 
16
16
  accepts_nested_attributes_for :categories, allow_destroy: true
17
17
 
18
- after_create :set_position
18
+ after_create :set_default_position
19
+ after_create :create_field_instances
19
20
 
20
21
  # Slug
21
22
  extend FriendlyId
@@ -51,17 +52,23 @@ module Binda
51
52
  1000
52
53
  end
53
54
 
55
+ # Create field instances for the current component
56
+ def create_field_instances
57
+ instance_field_settings = FieldSetting
58
+ .includes(field_group: [ :structure ])
59
+ .where(binda_structures: { id: self.structure.id })
60
+ instance_field_settings.each do |field_setting|
61
+ field_setting.create_field_instance_for(self)
62
+ end
63
+ end
64
+
54
65
  private
55
66
 
56
- # By default a newly created component gets the last position
57
- def set_position
58
- # check whats the latest component
59
- last_position = self.structure.components.order(:position).pluck(:position).last
60
- # if latest component position isn't set get position by counting the amount of components
61
- last_position = self.structure.components.length if last_position.nil?
62
- # update component
63
- self.update_attributes(position: last_position + 1)
64
- end
67
+ def set_default_position
68
+ Component
69
+ .where(structure_id: self.structure_id)
70
+ .each{|component| component.increment(:position).save!}
71
+ end
65
72
 
66
73
  end
67
74
  end
@@ -2,12 +2,8 @@ module Binda
2
2
  # This class provides support for dates.
3
3
  class Date < ApplicationRecord
4
4
 
5
- # Associations
6
- belongs_to :fieldable, polymorphic: true
7
- belongs_to :field_setting
8
-
9
- validates :fieldable_id, presence: true
10
- validates :fieldable_type, presence: true
5
+ include Fields
6
+ include FieldUniqueness
11
7
 
12
8
  end
13
9
  end
@@ -20,7 +20,7 @@ module Binda
20
20
  extend FriendlyId
21
21
  friendly_id :default_slug, use: [:slugged, :finders]
22
22
 
23
- after_create :update_position
23
+ after_create :set_default_position
24
24
 
25
25
  # Friendly id preference on slug generation
26
26
  #
@@ -58,10 +58,12 @@ module Binda
58
58
 
59
59
  private
60
60
 
61
- def update_position
62
- if self.position.nil?
63
- self.update_attribute('position', self.structure.field_groups.length)
64
- end
61
+ # Set a default position if isn't set and updates all related field settings
62
+ # Update all field settings related to the one created
63
+ def set_default_position
64
+ FieldGroup
65
+ .where(structure_id: self.structure_id)
66
+ .each{|field_group| field_group.increment(:position).save!}
65
67
  end
66
68
 
67
69
  end
@@ -84,9 +84,11 @@ module Binda
84
84
  self.class.reset_field_settings_array
85
85
  convert_allow_null__nil_to_false
86
86
  create_field_instances
87
+ set_default_position
87
88
  end
88
89
 
89
90
  after_update do
91
+ self.class.remove_orphan_fields
90
92
  if %w(radio selection checkbox).include?(self.field_type) && self.choices.empty?
91
93
  check_allow_null_option
92
94
  end
@@ -108,10 +110,10 @@ module Binda
108
110
  validates :field_type, inclusion: {
109
111
  in: [ *FieldSetting.get_field_classes.map{ |fc| fc.to_s.underscore } ],
110
112
  allow_nil: false,
111
- message: -> (field_setting) {
113
+ message: -> (field_setting, _) {
112
114
  I18n.t(
113
115
  "binda.field_setting.validation_message.field_type",
114
- { arg1: field_setting.name, arg2: "#{FieldSetting.get_field_classes.join(", ")}" }
116
+ { arg1: field_setting.name, arg2: FieldSetting.get_field_classes.join(", ") }
115
117
  )
116
118
  }
117
119
  }
@@ -144,6 +146,7 @@ module Binda
144
146
  #
145
147
  # It generates 4 possible slugs before falling back to FriendlyId default behaviour
146
148
  def default_slug
149
+ return self.name if self.field_group_id.nil?
147
150
  slug = ''
148
151
  slug << self.field_group.structure.name
149
152
  slug << '-'
@@ -249,25 +252,25 @@ module Binda
249
252
  def create_field_instances
250
253
  # Get the structure
251
254
  structure = self.structures.includes(:board, components: [:repeaters]).first
252
- field_class = "Binda::#{self.field_type.classify}"
253
255
  structure.components.each do |component|
254
- create_field_instances_for_instance(component, field_class, self.id)
256
+ create_field_instance_for(component)
255
257
  end
256
- create_field_instances_for_instance(structure.board, field_class, self.id) if structure.board.present?
258
+ create_field_instance_for(structure.board) if structure.board.present?
257
259
  end
258
260
 
259
261
  def create_field_instance_for(instance)
262
+ field_class = "Binda::#{self.field_type.classify}"
260
263
  if self.is_root?
261
- create_field_instances_for_instance(instance, field_class, self.id)
264
+ create_field_instance_for_instance(instance, field_class, self.id)
262
265
  else
263
266
  instance.repeaters.select{|r| r.field_setting_id == self.parent_id}.each do |repeater|
264
- create_field_instances_for_instance(repeater, field_class, self.id)
267
+ create_field_instance_for_instance(repeater, field_class, self.id)
265
268
  end
266
269
  end
267
270
  end
268
271
 
269
272
  # Helper for create_field_instances method
270
- def create_field_instances_for_instance(instance, field_class, field_setting_id)
273
+ def create_field_instance_for_instance(instance, field_class, field_setting_id)
271
274
  field_class.constantize.find_or_create_by!(
272
275
  field_setting_id: field_setting_id,
273
276
  fieldable_id: instance.id,
@@ -304,5 +307,63 @@ module Binda
304
307
  end
305
308
  end
306
309
 
310
+ # Remove all orphan fields
311
+ #
312
+ # Specifically:
313
+ # - all fields where their field setting doesn't exist anymore
314
+ # - all fields where their field setting has change type
315
+ #
316
+ # Used by task `rails binda:remove_orphan_fields`
317
+ def self.remove_orphan_fields
318
+ FieldSetting.get_field_classes.each do |field_class|
319
+ FieldSetting.remove_orphan_fields_with_no_settings(field_class)
320
+ FieldSetting.remove_orphan_fields_with_wrong_field_type(field_class)
321
+ end
322
+ end
323
+
324
+ # Remove orphan fields that isn't associated to any field setting
325
+ def self.remove_orphan_fields_with_no_settings(field_class)
326
+ "Binda::#{field_class}"
327
+ .constantize
328
+ .includes(:field_setting)
329
+ .where(binda_field_settings: {id: nil})
330
+ .each do |s|
331
+ s.destroy!
332
+ puts "Binda::#{field_class} with id ##{s.id} successfully destroyed"
333
+ end
334
+ end
335
+
336
+ # Remove orphan fields with wrong field type
337
+ def self.remove_orphan_fields_with_wrong_field_type(field_class)
338
+ field_types = []
339
+ case field_class
340
+ when 'Selection'
341
+ field_types = %w(selection checkbox radio)
342
+ when 'Text'
343
+ field_types = %w(string text)
344
+ else
345
+ field_types = [ field_class.underscore ]
346
+ end
347
+ "Binda::#{field_class}"
348
+ .constantize
349
+ .includes(:field_setting)
350
+ .where.not(binda_field_settings: {field_type: field_types})
351
+ .each do |s|
352
+ s.destroy!
353
+ puts "Binda::#{field_class} with id ##{s.id} but wrong type successfully destroyed"
354
+ end
355
+ end
356
+
357
+ # Set a default position if isn't set and updates all related field settings
358
+ # Update all field settings related to the one created
359
+ def set_default_position
360
+ FieldSetting
361
+ .where(
362
+ field_group_id: self.field_group_id,
363
+ ancestry: self.ancestry
364
+ )
365
+ .each{|field_setting| field_setting.increment(:position).save!}
366
+ end
367
+
307
368
  end
308
369
  end