active_scaffold 4.1.6 → 4.2.0

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +27 -0
  3. data/README.md +6 -5
  4. data/app/assets/javascripts/jquery/active_scaffold.js +98 -47
  5. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +15 -2
  6. data/app/assets/stylesheets/active_scaffold_images.scss +6 -0
  7. data/app/assets/stylesheets/{active_scaffold_layout.css → active_scaffold_layout.scss} +104 -4
  8. data/app/assets/stylesheets/tiny_mce_bridge.scss +11 -0
  9. data/app/views/active_scaffold_overrides/_base_form.html.erb +3 -2
  10. data/app/views/active_scaffold_overrides/_field_search.html.erb +2 -2
  11. data/app/views/active_scaffold_overrides/_form.html.erb +14 -4
  12. data/app/views/active_scaffold_overrides/_form_association.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +5 -11
  14. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  15. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -3
  16. data/app/views/active_scaffold_overrides/_new_record.js.erb +3 -1
  17. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +1 -1
  18. data/app/views/active_scaffold_overrides/_render_field.js.erb +67 -36
  19. data/app/views/active_scaffold_overrides/_update_field_on_create.js.erb +41 -6
  20. data/app/views/active_scaffold_overrides/action_links_menu.js.erb +1 -0
  21. data/config/locales/de.yml +9 -0
  22. data/config/locales/en.yml +11 -0
  23. data/config/locales/es.yml +8 -0
  24. data/config/locales/fr.yml +8 -0
  25. data/config/locales/hu.yml +8 -0
  26. data/config/locales/ja.yml +8 -0
  27. data/config/locales/ru.yml +8 -0
  28. data/lib/active_scaffold/actions/common_search.rb +2 -0
  29. data/lib/active_scaffold/actions/core.rb +47 -23
  30. data/lib/active_scaffold/actions/create.rb +2 -0
  31. data/lib/active_scaffold/actions/delete.rb +6 -0
  32. data/lib/active_scaffold/actions/field_search.rb +36 -11
  33. data/lib/active_scaffold/actions/list.rb +26 -8
  34. data/lib/active_scaffold/actions/mark.rb +6 -0
  35. data/lib/active_scaffold/actions/nested.rb +2 -0
  36. data/lib/active_scaffold/actions/search.rb +7 -0
  37. data/lib/active_scaffold/actions/show.rb +6 -0
  38. data/lib/active_scaffold/actions/subform.rb +2 -0
  39. data/lib/active_scaffold/actions/update.rb +8 -1
  40. data/lib/active_scaffold/active_record_permissions.rb +3 -3
  41. data/lib/active_scaffold/attribute_params.rb +35 -17
  42. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +2 -0
  43. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +10 -9
  44. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +10 -3
  45. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +2 -0
  46. data/lib/active_scaffold/bridges/active_storage.rb +2 -0
  47. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +2 -0
  48. data/lib/active_scaffold/bridges/ancestry.rb +2 -0
  49. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +2 -0
  50. data/lib/active_scaffold/bridges/bitfields/list_ui.rb +2 -0
  51. data/lib/active_scaffold/bridges/bitfields.rb +2 -0
  52. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -6
  53. data/lib/active_scaffold/bridges/cancan.rb +2 -0
  54. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +2 -0
  55. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +2 -0
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +3 -1
  57. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -0
  58. data/lib/active_scaffold/bridges/carrierwave.rb +2 -0
  59. data/lib/active_scaffold/bridges/chosen/helpers.rb +13 -4
  60. data/lib/active_scaffold/bridges/chosen.rb +2 -0
  61. data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +2 -0
  62. data/lib/active_scaffold/bridges/country_select.rb +2 -0
  63. data/lib/active_scaffold/bridges/date_picker/ext.rb +6 -0
  64. data/lib/active_scaffold/bridges/date_picker/helper.rb +7 -3
  65. data/lib/active_scaffold/bridges/date_picker.rb +2 -0
  66. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +2 -0
  67. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +2 -0
  68. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -1
  69. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +2 -0
  70. data/lib/active_scaffold/bridges/dragonfly.rb +2 -0
  71. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +2 -0
  72. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +10 -9
  73. data/lib/active_scaffold/bridges/file_column/form_ui.rb +2 -0
  74. data/lib/active_scaffold/bridges/file_column/list_ui.rb +2 -0
  75. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +2 -0
  76. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +2 -0
  77. data/lib/active_scaffold/bridges/file_column.rb +2 -0
  78. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.rb +65 -0
  79. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.treetop +31 -0
  80. data/lib/active_scaffold/bridges/logical_query_parser.rb +9 -0
  81. data/lib/active_scaffold/bridges/paper_trail/actions.rb +2 -0
  82. data/lib/active_scaffold/bridges/paper_trail/config.rb +2 -0
  83. data/lib/active_scaffold/bridges/paper_trail/helper.rb +2 -0
  84. data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +2 -0
  85. data/lib/active_scaffold/bridges/paper_trail.rb +2 -0
  86. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -1
  87. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +2 -0
  88. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +2 -0
  89. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +12 -12
  90. data/lib/active_scaffold/bridges/paperclip.rb +2 -0
  91. data/lib/active_scaffold/bridges/record_select/helpers.rb +19 -11
  92. data/lib/active_scaffold/bridges/record_select.rb +2 -0
  93. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +2 -0
  94. data/lib/active_scaffold/bridges/semantic_attributes.rb +2 -0
  95. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  96. data/lib/active_scaffold/bridges/tiny_mce.rb +6 -0
  97. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +2 -0
  98. data/lib/active_scaffold/bridges/usa_state_select.rb +2 -0
  99. data/lib/active_scaffold/bridges.rb +2 -0
  100. data/lib/active_scaffold/config/base.rb +12 -7
  101. data/lib/active_scaffold/config/core.rb +26 -23
  102. data/lib/active_scaffold/config/create.rb +2 -0
  103. data/lib/active_scaffold/config/delete.rb +2 -0
  104. data/lib/active_scaffold/config/field_search.rb +2 -0
  105. data/lib/active_scaffold/config/form.rb +11 -1
  106. data/lib/active_scaffold/config/list.rb +7 -7
  107. data/lib/active_scaffold/config/mark.rb +2 -0
  108. data/lib/active_scaffold/config/nested.rb +28 -0
  109. data/lib/active_scaffold/config/search.rb +2 -0
  110. data/lib/active_scaffold/config/show.rb +2 -0
  111. data/lib/active_scaffold/config/subform.rb +2 -0
  112. data/lib/active_scaffold/config/update.rb +3 -1
  113. data/lib/active_scaffold/configurable.rb +4 -2
  114. data/lib/active_scaffold/constraints.rb +2 -0
  115. data/lib/active_scaffold/core.rb +14 -4
  116. data/lib/active_scaffold/data_structures/action_columns.rb +3 -1
  117. data/lib/active_scaffold/data_structures/action_link.rb +10 -0
  118. data/lib/active_scaffold/data_structures/action_link_separator.rb +2 -0
  119. data/lib/active_scaffold/data_structures/action_links.rb +32 -21
  120. data/lib/active_scaffold/data_structures/actions.rb +4 -2
  121. data/lib/active_scaffold/data_structures/association/abstract.rb +4 -2
  122. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +4 -2
  123. data/lib/active_scaffold/data_structures/association/active_record.rb +3 -9
  124. data/lib/active_scaffold/data_structures/association/mongoid.rb +4 -2
  125. data/lib/active_scaffold/data_structures/association.rb +2 -0
  126. data/lib/active_scaffold/data_structures/bridge.rb +3 -1
  127. data/lib/active_scaffold/data_structures/column.rb +37 -3
  128. data/lib/active_scaffold/data_structures/columns.rb +4 -2
  129. data/lib/active_scaffold/data_structures/filter.rb +3 -3
  130. data/lib/active_scaffold/data_structures/filter_option.rb +2 -0
  131. data/lib/active_scaffold/data_structures/filters.rb +3 -3
  132. data/lib/active_scaffold/data_structures/nested_info.rb +4 -2
  133. data/lib/active_scaffold/data_structures/set.rb +8 -10
  134. data/lib/active_scaffold/data_structures/sorting.rb +5 -7
  135. data/lib/active_scaffold/engine.rb +3 -4
  136. data/lib/active_scaffold/extensions/action_controller_rendering.rb +2 -0
  137. data/lib/active_scaffold/extensions/action_controller_rescueing.rb +2 -0
  138. data/lib/active_scaffold/extensions/action_view_rendering.rb +2 -0
  139. data/lib/active_scaffold/extensions/connection_adapter.rb +2 -0
  140. data/lib/active_scaffold/extensions/ice_nine.rb +2 -0
  141. data/lib/active_scaffold/extensions/localize.rb +2 -0
  142. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +2 -0
  143. data/lib/active_scaffold/extensions/paginator_extensions.rb +3 -1
  144. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -0
  145. data/lib/active_scaffold/extensions/to_label.rb +2 -0
  146. data/lib/active_scaffold/extensions/unsaved_associated.rb +10 -8
  147. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -0
  148. data/lib/active_scaffold/finder.rb +57 -18
  149. data/lib/active_scaffold/helpers/action_link_helpers.rb +112 -37
  150. data/lib/active_scaffold/helpers/association_helpers.rb +4 -2
  151. data/lib/active_scaffold/helpers/controller_helpers.rb +2 -0
  152. data/lib/active_scaffold/helpers/filter_helpers.rb +11 -3
  153. data/lib/active_scaffold/helpers/form_column_helpers.rb +98 -71
  154. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -0
  155. data/lib/active_scaffold/helpers/id_helpers.rb +2 -0
  156. data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -5
  157. data/lib/active_scaffold/helpers/pagination_helpers.rb +3 -1
  158. data/lib/active_scaffold/helpers/search_column_helpers.rb +19 -9
  159. data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -2
  160. data/lib/active_scaffold/helpers/tabs_helpers.rb +5 -3
  161. data/lib/active_scaffold/helpers/view_helpers.rb +3 -3
  162. data/lib/active_scaffold/marked_model.rb +6 -5
  163. data/lib/active_scaffold/orm_checks.rb +2 -0
  164. data/lib/active_scaffold/paginator.rb +4 -1
  165. data/lib/active_scaffold/registry.rb +2 -0
  166. data/lib/active_scaffold/responds_to_parent.rb +2 -0
  167. data/lib/active_scaffold/tableless.rb +23 -13
  168. data/lib/active_scaffold/version.rb +4 -2
  169. data/lib/active_scaffold.rb +10 -2
  170. data/lib/generators/active_scaffold/controller/USAGE +19 -0
  171. data/lib/generators/active_scaffold/controller/controller_generator.rb +29 -0
  172. data/lib/generators/active_scaffold/install/USAGE +2 -0
  173. data/lib/generators/active_scaffold/{install_generator.rb → install/install_generator.rb} +10 -6
  174. data/lib/generators/active_scaffold/resource/USAGE +29 -0
  175. data/lib/generators/active_scaffold/resource/resource_generator.rb +30 -0
  176. data/lib/tasks/brakeman.rake +2 -0
  177. data/shoulda_macros/macros.rb +2 -0
  178. metadata +19 -11
  179. data/lib/generators/active_scaffold/controller_generator.rb +0 -49
  180. data/lib/generators/active_scaffold/resource_generator.rb +0 -56
  181. /data/lib/generators/{templates → active_scaffold/controller/templates}/controller.rb +0 -0
  182. /data/lib/generators/{templates → active_scaffold/controller/templates}/helper.rb +0 -0
@@ -10,7 +10,7 @@
10
10
  end
11
11
  end
12
12
  disable_required_for_new = @disable_required_for_new
13
- @disable_required_for_new = !show_blank_record.nil? unless column.association.singular? && column.required?(action_for_validation?(parent_record))
13
+ @disable_required_for_new = !show_blank_record.nil? unless column.association.singular? && column.required?(action_for_validation(parent_record))
14
14
  subform_div_id = "#{sub_form_id(association: column.name, tab_id: tab_id, id: parent_record.id || generated_id(parent_record) || 99_999_999_999)}-div"
15
15
 
16
16
  # render footer before rendering associated records, fixes create new on self-associations
@@ -25,7 +25,7 @@
25
25
  column_tag ||= :td
26
26
  error_tag ||= :tr
27
27
  error_inner_tag ||= :td
28
- default_col_class = []
28
+ default_col_class = ['form-element']
29
29
  flatten ||= false
30
30
  end
31
31
  index ||= form_association_record_counter ||= nil
@@ -52,8 +52,8 @@
52
52
  columns_length += 1
53
53
  show_actions = true
54
54
 
55
- col_class = default_col_class.clone
56
- col_class << 'required' if column.required?(action_for_validation?(record))
55
+ col_class = default_col_class.dup
56
+ col_class << 'required' if column.required?(action_for_validation(record))
57
57
  col_class << column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
58
58
  col_class << 'hidden' if column_renders_as(column) == :hidden
59
59
  -%>
@@ -63,13 +63,7 @@
63
63
  <% end -%>
64
64
  <% if show_actions -%>
65
65
  <%= content_tag column_tag, class: 'actions' do %>
66
- <% if record_column.association.collection? && !locked %>
67
- <%
68
- auth = %i[destroy delete_all delete].exclude?(record_column.association.dependent)
69
- auth, reason = record.authorized_for?(crud_type: :delete, reason: true) unless auth
70
- %>
71
- <%= auth ? link_to(as_(:remove), '#', class: 'destroy', id: "#{options[:id]}-destroy", data: {delete_id: tr_id}) : reason %>
72
- <% end %>
66
+ <%= active_scaffold_subform_record_actions(record_column, record, locked, scope) %>
73
67
  <% unless record.new_record? %>
74
68
  <input type="hidden" name="<%= options[:name] -%>" id="<%= options[:id] -%>" value="<%= record.id -%>" />
75
69
  <% end -%>
@@ -83,7 +77,7 @@
83
77
  <% columns_group.each_column(for: record.class, crud_type: :read, flatten: true) do |col| %>
84
78
  <%
85
79
  col_class = default_col_class.clone
86
- col_class << 'required' if col.required?(action_for_validation?(record))
80
+ col_class << 'required' if col.required?(action_for_validation(record))
87
81
  col_class << col.css_class unless col.css_class.nil? || col.css_class.is_a?(Proc)
88
82
  col_class << 'hidden' if column_renders_as(col) == :hidden
89
83
  %>
@@ -3,7 +3,7 @@
3
3
  header_record_class = show_blank_record&.class || column.association.klass
4
4
  record_partial_locals = {scope: scope, parent_record: parent_record, column: column, columns: local_assigns[:columns], layout: :horizontal}
5
5
  -%>
6
- <%= render 'horizontal_subform_header', parent_record: parent_record, record_class: header_record_class, parent_column: column, columns: local_assigns[:columns] %>
6
+ <%= render 'horizontal_subform_header', parent_record: parent_record, record_class: header_record_class, parent_column: column, columns: local_assigns[:columns], scope: scope %>
7
7
 
8
8
  <%= render partial: 'form_association_record', collection: associated, as: :record, locals: record_partial_locals %>
9
9
  <%= render 'form_association_record', record_partial_locals.merge(locked: true, index: associated.size, record: show_blank_record) if show_blank_record %>
@@ -9,9 +9,7 @@
9
9
  -%>
10
10
  <th class="<%= "#{column.name}-column #{'required' if column.required?} #{'hidden' if hidden}" %>">
11
11
  <label><%= subform_label(column, hidden) %></label>
12
- <% if column.description.present? -%>
13
- <span class="description"><%= column.description %></span>
14
- <% end -%>
12
+ <%= column_description(column, nil, scope) %>
15
13
  </th>
16
14
  <% end -%>
17
15
  <th></th>
@@ -8,7 +8,9 @@
8
8
  <% end %>
9
9
  <% elsif active_scaffold_config.create.refresh_list %>
10
10
  <%= render 'refresh_list', no_history: true %>
11
- <% elsif params[:parent_controller].nil? %>
11
+ <% elsif params[:parent_controller].present? %>
12
+ if (action_link) action_link.refresh();
13
+ <% else %>
12
14
  <% new_row = render list_record_view, record: @saved_record || @record %>
13
15
  ActiveScaffold.create_record_row(action_link ? action_link.scaffold() : '<%= active_scaffold_id %>', '<%= escape_javascript(new_row) %>', <%= {insert_at: insert_at}.to_json.html_safe %>);
14
16
  <%= render 'update_calculations' %>
@@ -19,6 +19,6 @@
19
19
 
20
20
  <% if !@auto_pagination && !@popstate && !embedded? && !local_assigns[:no_history] -%>
21
21
  if (!jQuery('#<%= active_scaffold_id %>').is('.active-scaffold .active-scaffold')) {
22
- ActiveScaffold.add_to_history(<%=raw request.original_url.to_json %>, <%=raw history_state.to_json %>);
22
+ ActiveScaffold.add_to_history(<%=raw (local_assigns[:history_url] || request.original_url).to_json %>, <%=raw history_state.to_json %>);
23
23
  }
24
24
  <% end -%>
@@ -1,44 +1,75 @@
1
1
  <%
2
- column =
3
- if render_field.is_a? ActiveScaffold::DataStructures::Column
4
- render_field
5
- else
6
- active_scaffold_config.columns[render_field]
7
- end
8
- return unless @main_columns.include? column.name
9
- @rendered ||= Set.new
10
- return if @rendered.include? column.name
11
- @rendered << column.name
12
- if @form_action == :field_search
13
- form_ui = column.search_ui
14
- else
15
- renders_as = column_renders_as(column)
16
- form_ui = column.form_ui
17
- end
2
+ record ||= @record
3
+ active_scaffold_config ||= self.active_scaffold_config
4
+ if render_field.is_a?(Hash)
5
+ traverse ||= []
6
+ render_field.each do |assoc_name, columns|
7
+ if assoc_name == :__root__
8
+ config = params[:parent_controller] ? active_scaffold_config_for(params[:parent_controller].singularize.camelize) : controller.active_scaffold_config
9
+ value = @form_record
10
+ else
11
+ next if traverse.blank? && @main_columns.exclude?(assoc_name)
12
+ assoc_column = active_scaffold_config.columns[assoc_name]
13
+ raise "#{assoc_name} is not an association column" unless assoc_column&.association
14
+ config = active_scaffold_config_for(assoc_column.association.klass)
15
+ value = record.send(assoc_name)
16
+ traverse_by_record = assoc_column.association.collection?
17
+ end
18
+ next if value.nil?
18
19
 
19
- column_css_class = column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
20
- options = {field_class: "#{column.name}-input", hidden: form_ui == :hidden}
21
- options[:subform_class] = "#{column.name}-sub-form" if column.association
22
- options[:attrs] =
23
- if renders_as == :subform
24
- active_scaffold_subform_attributes(column, column_css_class)
25
- else
26
- {class: "form-element #{:required if column.required?(@form_action)} #{column.form_ui} #{column_css_class}", id: ''}
20
+ columns = [columns] unless columns.is_a?(Array)
21
+ sub_form = assoc_name == :__root__ ? assoc_name : ".#{assoc_name}-sub-form .sub-form-record"
22
+ Array(value).each do |r|
23
+ temp_id = @new_records&.dig(config.model)&.key(r) if traverse_by_record && r.id.nil?
24
+ step = traverse_by_record ? "#{sub_form}:has([id$=\"#{assoc_name}_#{r.id || temp_id}\"])" : sub_form
25
+ next_scope = column_scope(assoc_column, scope, r, temp_id) unless assoc_name == :__root__
26
+ %>
27
+ <%= render(partial: 'render_field', collection: columns, locals: {source_id: source_id, scope: next_scope, record: r, active_scaffold_config: config, traverse: traverse + [step]}) %>
28
+ <%
29
+ end
27
30
  end
28
- html =
29
- if scope
30
- readonly = @record.readonly? || !@record.authorized_for?(crud_type: :update)
31
- crud_type = @record.id.nil? ? :create : (readonly ? :read : :update) # don't use new_record?, it's always true in render_field action
32
- # subform.columns.to_a.include? so it doesn't check inside subgroups
33
- active_scaffold_render_subform_column(column, scope, crud_type, readonly, active_scaffold_config.subform.columns.to_a.exclude?(column.name), @record)
34
- elsif @form_action == :field_search
35
- search_attribute(column, @record)
31
+ else
32
+ column =
33
+ if render_field.is_a? ActiveScaffold::DataStructures::Column
34
+ render_field
35
+ else
36
+ active_scaffold_config.columns[render_field]
37
+ end
38
+ return if column.nil? # using hash may include __root__ to update parent columns when used as subform, and fail if it can be in different model's form, or when edited without subform
39
+ return if local_assigns[:traverse].nil? && @main_columns.exclude?(column.name)
40
+ rendered = (@rendered ||= {})[record] ||= Set.new
41
+ return if rendered.include? column.name
42
+ rendered << column.name
43
+ if @form_action == :field_search
44
+ form_ui = column.search_ui
36
45
  else
37
- render_column(column, @record, renders_as, scope)
46
+ renders_as = column_renders_as(column)
47
+ form_ui = column.form_ui
38
48
  end
49
+
50
+ column_css_class = column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
51
+ options = {field_class: "#{column.name}-input", hidden: form_ui == :hidden}
52
+ options[:subform_class] = "#{column.name}-sub-form" if column.association
53
+ options[:attrs] =
54
+ if renders_as == :subform
55
+ active_scaffold_subform_attributes(column, column_css_class)
56
+ else
57
+ {class: "form-element #{:required if column.required?(@form_action)} #{column.form_ui} #{column_css_class}", id: ''}
58
+ end
59
+ options[:traverse] = traverse if local_assigns[:traverse]
60
+ html =
61
+ if scope
62
+ readonly = record.readonly? || !record.authorized_for?(crud_type: :update)
63
+ crud_type = record.id.nil? ? :create : (readonly ? :read : :update) # don't use new_record?, it's always true in render_field action
64
+ # subform.columns.to_a.include? so it doesn't check inside subgroups
65
+ active_scaffold_render_subform_column(column, scope, crud_type, readonly, active_scaffold_config.subform.columns.to_a.exclude?(column.name), record)
66
+ elsif @form_action == :field_search
67
+ search_attribute(column, record)
68
+ else
69
+ render_column(column, record, renders_as, scope)
70
+ end
39
71
  -%>
40
72
 
41
73
  ActiveScaffold.render_form_field('<%= source_id %>','<%= escape_javascript(html) %>', <%= options.to_json.html_safe %>);
42
- <%if column.update_columns.present?%>
43
- <%= render(partial: 'render_field', collection: column.update_columns, locals: {source_id: source_id, scope: scope}) %>
44
- <%end%>
74
+ <%= render(partial: 'render_field', collection: column.update_columns, locals: local_assigns) if column.update_columns.present? %>
75
+ <% end %>
@@ -7,14 +7,49 @@ var field = jQuery('#<%= params[:from_field] %>');
7
7
  field_options[:class] = "#{field_options[:class]} update_form" if field_options&.dig('data-update_url')
8
8
  %>
9
9
  if (field.is('select')) {
10
- field.append('<%= j content_tag(:option, label, value: id) %>');
11
- field.val(<%= id %>);
10
+ if (!field.find('option[value="<%= id %>"]').length) field.append('<%= j content_tag(:option, label, value: id) %>');
11
+ if (field.prop("multiple")) {
12
+ var current = field.val() || []; // val() returns null if nothing selected
13
+ current.push(<%= id %>);
14
+ field.val(current);
15
+ } else {
16
+ field.val(<%= id %>);
17
+ }
18
+ if (field.is('.chosen')) field.trigger('chosen:updated');
12
19
  } else if (field.is('input.recordselect')) {
13
- field.val('<%= j label %>').addClass('selected');
14
- field.next().val(<%= id %>);
20
+ var rs = field.siblings('.record-select-list').data('recordselect');
21
+ if (rs) { // RS multiple
22
+ rs.add(<%= id %>, '<%= j label %>');
23
+ } else {
24
+ field.val('<%= j label %>').addClass('selected');
25
+ field.next().val(<%= id %>);
26
+ }
15
27
  } else if (field.is('.new-radio-container')) {
16
- field.append('<%= j active_scaffold_radio_option(@record, id, column, field_options, ui_options: column.form_ui_options || column.options) if column %>');
28
+ if (!field.parent().find('input[type=radio][value="<%= id %>"]').length) {
29
+ field.append('<%= j active_scaffold_radio_option(@record, id, column, field_options, ui_options: column.form_ui_options || column.options) if column %>');
30
+ } else field = field.parent().find('input[type=radio][value="<%= id %>"]').prop('checked', true);
31
+ } else if (field.is('.checkbox-list')) {
32
+ var list = field;
33
+ if (list.is('.draggable-list')) {
34
+ field = field.closest('.draggable-lists-container');
35
+ list = field.find('.draggable-list.selected');
36
+ }
37
+ if (!field.find('input[type=checkbox][value="<%= id %>"]').length) {
38
+ <%
39
+ ui_options = column&.form_ui_options || column&.options
40
+ label_method = ui_options&.dig(:label_method) || :to_label
41
+ cb_id = "#{field_options[:id]}_INDEX_id"
42
+ html = active_scaffold_checkbox_option(@record, label_method, [id], {name: "#{field_options[:name]}[]", id: cb_id}, ui_options&.dig(:item_options) || {})
43
+ %>
44
+ var cb_id = '<%= cb_id %>'.replace('INDEX', field.find('input[type=checkbox]').length);
45
+ list.append('<%= j html %>')
46
+ list.find('#<%= cb_id %>').attr('id', cb_id);
47
+ list.find('[for="<%= cb_id %>"]').attr('for', cb_id);
48
+ } else {
49
+ field = field.find('input[type=checkbox][value="<%= id %>"]').prop('checked', true);
50
+ if (list.is('.draggable-list')) list.append(field.parent());
51
+ }
17
52
  }
18
53
  field.trigger('change');
19
- var action_link = ActiveScaffold.ActionLink.get(field.parent().find('a.as_action'));
54
+ var action_link = ActiveScaffold.ActionLink.get(field.closest('.select-field').parent().find('a.as_action'));
20
55
  if (action_link) action_link.close();
@@ -0,0 +1 @@
1
+ <%= display_dynamic_action_group(@action_links, display_action_links(@action_links, @record, for: @record, output: []).compact, @record) %>
@@ -11,6 +11,9 @@ de:
11
11
  add: Hinzufügen
12
12
  add_existing: Existierenden Eintrag hinzufügen
13
13
  add_existing_model: Existierende %{model} hinzufügen
14
+ add_model: "%{model} hinzufügen"
15
+ all_tokens:
16
+ any_token:
14
17
  apply: Akzeptieren
15
18
  are_you_sure_to_delete: Sind Sie sicher?
16
19
  average: Durchschnitt
@@ -77,6 +80,7 @@ de:
77
80
  internal_error: Fehler bei der Verarbeitung
78
81
  live_search: Live-Suche
79
82
  loading: Lade…
83
+ logical_search:
80
84
  mark_all_records: Alle auswählen
81
85
  maximum: Maximum
82
86
  minimum: Minimum
@@ -151,3 +155,8 @@ de:
151
155
  time:
152
156
  formats:
153
157
  picker: "%d.%m.%Y %H:%M"
158
+ datetime:
159
+ prompts:
160
+ millisec:
161
+ microsec:
162
+
@@ -11,6 +11,9 @@ en:
11
11
  add: Add
12
12
  add_existing: Add Existing
13
13
  add_existing_model: Add Existing %{model}
14
+ add_model: Add %{model}
15
+ all_tokens: All keywords
16
+ any_token: Any keyword
14
17
  apply: Apply
15
18
  are_you_sure_to_delete: Are you sure you want to delete %{label}?
16
19
  average: Average
@@ -77,6 +80,7 @@ en:
77
80
  internal_error: Request Failed
78
81
  live_search: Live Search
79
82
  loading: Loading…
83
+ logical_search: Logical Search
80
84
  mark_all_records: Mark all
81
85
  maximum: Maximum
82
86
  minimum: Minimum
@@ -151,3 +155,10 @@ en:
151
155
  time:
152
156
  formats:
153
157
  picker: "%a, %d %b %Y %H:%M:%S"
158
+ datetime:
159
+ prompts:
160
+ hour: Hour
161
+ minute: Minute
162
+ second: Second
163
+ millisec: Millisecond
164
+ microsec: Microsecond
@@ -11,6 +11,9 @@ es:
11
11
  add: Añadir
12
12
  add_existing: Añadir Existente
13
13
  add_existing_model: Añadir %{model} Existente
14
+ add_model: Añadir %{model}
15
+ all_tokens:
16
+ any_token:
14
17
  apply: Aplicar
15
18
  are_you_sure_to_delete: "¿Estás seguro de que quieres borrar %{label}?"
16
19
  average: Media
@@ -79,6 +82,7 @@ es:
79
82
  internal_error: Petición fallida
80
83
  live_search: Buscar en Vivo
81
84
  loading: Cargando…
85
+ logical_search: Búsqueda Logica
82
86
  mark_all_records: Seleccionar todos
83
87
  maximum: Máximo
84
88
  minimum: Mínimo
@@ -153,3 +157,7 @@ es:
153
157
  time:
154
158
  formats:
155
159
  picker: "%a, %d %b %Y %H:%M:%S"
160
+ datetime:
161
+ prompts:
162
+ millisec: Milisegundo
163
+ microsec: Microsegundo
@@ -11,6 +11,9 @@ fr:
11
11
  add: Ajouter
12
12
  add_existing: Ajouter un(e) existant(e)
13
13
  add_existing_model: Ajouter un(e) %{model} existant(e)
14
+ add_model: Ajouter un(e) %{model}
15
+ all_tokens:
16
+ any_token:
14
17
  apply: Appliquer
15
18
  are_you_sure_to_delete: Êtes vous sûr de vouloir supprimer %{label} ?
16
19
  average: Moyenne
@@ -77,6 +80,7 @@ fr:
77
80
  internal_error: Erreur de la requête
78
81
  live_search: Recherche en temps réel
79
82
  loading: Chargement…
83
+ logical_search:
80
84
  mark_all_records: Marquer tous
81
85
  maximum: Maximum
82
86
  minimum: Minimum
@@ -151,3 +155,7 @@ fr:
151
155
  time:
152
156
  formats:
153
157
  picker: "%a, %d %b %Y %H:%M:%S"
158
+ datetime:
159
+ prompts:
160
+ millisec:
161
+ microsec:
@@ -11,6 +11,9 @@ hu:
11
11
  add: Hozzáadás
12
12
  add_existing: Meglevő hozzáadása
13
13
  add_existing_model: Meglevő %{model} hozzáadása
14
+ add_model: "%{model} hozzáadása"
15
+ all_tokens:
16
+ any_token:
14
17
  apply: Apply
15
18
  are_you_sure_to_delete: Are you sure you want to delete %{label}?
16
19
  average: Average
@@ -77,6 +80,7 @@ hu:
77
80
  internal_error: A lekérés sikertelen
78
81
  live_search: Élő keresés
79
82
  loading: Betöltés…
83
+ logical_search:
80
84
  mark_all_records: Mark all
81
85
  maximum: Maximum
82
86
  minimum: Minimum
@@ -151,3 +155,7 @@ hu:
151
155
  time:
152
156
  formats:
153
157
  picker: "%a, %d %b %Y %H:%M:%S"
158
+ datetime:
159
+ prompts:
160
+ millisec:
161
+ microsec:
@@ -11,6 +11,9 @@ ja:
11
11
  add: 追加
12
12
  add_existing: 既存のものを追加
13
13
  add_existing_model: 既存の%{model}を追加
14
+ add_model: "%{model}を追加"
15
+ all_tokens:
16
+ any_token:
14
17
  apply: 適用
15
18
  are_you_sure_to_delete: "%{label}を消去してもよろしいですか?"
16
19
  average: 平均
@@ -77,6 +80,7 @@ ja:
77
80
  internal_error: リクエストが失敗しました
78
81
  live_search: その場で検索
79
82
  loading: 読み込み中…
83
+ logical_search:
80
84
  mark_all_records: すべて選択
81
85
  maximum: 最大値
82
86
  minimum: 最小値
@@ -151,3 +155,7 @@ ja:
151
155
  time:
152
156
  formats:
153
157
  picker: "%Y年%m月%d日(%a) %H:%M:%S"
158
+ datetime:
159
+ prompts:
160
+ millisec:
161
+ microsec:
@@ -11,6 +11,9 @@ ru:
11
11
  add: Добавить запись
12
12
  add_existing: Добавить существующую запись
13
13
  add_existing_model: "%{model}: добавить существующую запись"
14
+ add_model: "%{model}: добавить запись"
15
+ all_tokens: Todas las palabras
16
+ any_token: Cualquier palabra
14
17
  apply: Применить
15
18
  are_you_sure_to_delete: Удалить %{label}?
16
19
  average: Среднее
@@ -83,6 +86,7 @@ ru:
83
86
  internal_error: Внутренняя ошибка
84
87
  live_search: Поиск
85
88
  loading: Загрузка…
89
+ logical_search:
86
90
  mark_all_records: Отметить все
87
91
  maximum: Максимум
88
92
  minimum: Минимум
@@ -159,3 +163,7 @@ ru:
159
163
  time:
160
164
  formats:
161
165
  picker: "%a, %d %b %Y %H:%M:%S"
166
+ datetime:
167
+ prompts:
168
+ millisec:
169
+ microsec:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold::Actions
2
4
  module CommonSearch
3
5
  def self.included(base)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold::Actions
2
4
  module Core
3
5
  def self.included(base)
@@ -107,23 +109,21 @@ module ActiveScaffold::Actions
107
109
  id = params[:id]
108
110
  end
109
111
 
110
- # check permissions and support overriding to_param
111
- saved_record = find_if_allowed(id, :read) if id
112
- # call update_record_from_params with new_model
113
- # in other case some associations can be saved
114
- record = new_model
115
- copy_attributes(saved_record, record) if saved_record
116
- apply_constraints_to_record(record) unless scope
117
- create_association_with_parent record, check_match: true if nested?
112
+ # call update_record_from_params with new_model, in other case some associations can be saved
113
+ @form_record = new_model
114
+ # check permissions and support overriding to_param, preload associations
115
+ copy_data_from_saved_record(id, active_scaffold_config, @form_record) if id
116
+ apply_constraints_to_record(@form_record) unless scope
117
+ create_association_with_parent @form_record, check_match: true if nested?
118
118
  if @form_action == :field_search
119
- update_columns_from_params(record, columns, attributes || {}, :read, avoid_changes: true, search_attributes: true)
119
+ update_columns_from_params(@form_record, columns, attributes || {}, :read, avoid_changes: true, search_attributes: true)
120
120
  else
121
- update_record_from_params(record, columns, attributes || {}, true)
121
+ update_record_from_params(@form_record, columns, attributes || {}, true)
122
122
  end
123
123
  end
124
124
 
125
125
  def updated_record_with_column(column, value, scope)
126
- record = params[:id] ? copy_attributes(find_if_allowed(params[:id], :read)) : new_model
126
+ record = params[:id] ? copy_data_from_saved_record(params[:id]) : new_model
127
127
  apply_constraints_to_record(record) unless scope || params[:id]
128
128
  create_association_with_parent record, check_match: true if nested?
129
129
  if @form_action == :field_search && value.is_a?(Array) && column.association&.singular?
@@ -148,10 +148,8 @@ module ActiveScaffold::Actions
148
148
 
149
149
  def setup_parent
150
150
  cfg = main_form_controller.active_scaffold_config
151
- parent_model = cfg.model
152
- parent = parent_model.new
153
- copy_attributes(find_if_allowed(params[:parent_id], :read, parent_model), parent) if params[:parent_id]
154
- parent.id = params[:parent_id]
151
+ parent = cfg.model.new
152
+ copy_data_from_saved_record(params[:parent_id], cfg, parent) if params[:parent_id]
155
153
  apply_constraints_to_record(parent) unless params[:parent_id]
156
154
  if @column.send_form_on_update_column
157
155
  parent = update_record_from_params(parent, cfg.send(params[:parent_id] ? :update : :create).columns, params[:record], true)
@@ -163,7 +161,13 @@ module ActiveScaffold::Actions
163
161
  apply_constraints_to_record(parent, constraints: {nested.child_association.name => nested.parent_id})
164
162
  end
165
163
  end
166
- parent
164
+ @form_record = parent
165
+ end
166
+
167
+ def copy_data_from_saved_record(id, config = active_scaffold_config, record = nil)
168
+ preload_values = preload_for_form(config.update.columns) if config.actions.include?(:update)
169
+ saved_record = find_if_allowed(id, :read, config.model.preload(preload_values))
170
+ copy_attributes(saved_record, record).tap { |new_record| new_record.id = id }
167
171
  end
168
172
 
169
173
  def find_from_scope(parent, scope)
@@ -190,6 +194,9 @@ module ActiveScaffold::Actions
190
194
  def copy_attributes(orig, dst = nil)
191
195
  dst ||= orig.class.new
192
196
  orig.attributes.each { |attr, value| dst.send :write_attribute, attr, value }
197
+ orig.class.reflect_on_all_associations.each do |assoc|
198
+ dst.association(assoc.name).target = orig.association(assoc.name).target if orig.send(:association_cached?, assoc.name)
199
+ end
193
200
  dst.changes_applied
194
201
  dst
195
202
  end
@@ -204,6 +211,27 @@ module ActiveScaffold::Actions
204
211
  @parent_sti_controller
205
212
  end
206
213
 
214
+ def preload_for_form(columns, preloaded_models = [])
215
+ association_columns = []
216
+ columns.each_column(flatten: true, skip_authorization: true) do |column|
217
+ association_columns << column if column.association && column.subform_includes
218
+ end
219
+
220
+ association_columns.filter_map do |column|
221
+ if column.form_ui.nil? && column.subform_includes == true && preloaded_models.exclude?(column.association.klass)
222
+ config = active_scaffold_config_for(column.association.klass)
223
+ if config.actions.include?(:subform)
224
+ preload_values = preload_for_form(config.subform.columns, preloaded_models + [column.association.klass])
225
+ end
226
+ preload_values ? {column.name => preload_values} : column.name
227
+ elsif column.subform_includes != true
228
+ {column.name => column.subform_includes}
229
+ else
230
+ column.name
231
+ end
232
+ end
233
+ end
234
+
207
235
  # override this method if you want to do something after render_field
208
236
  def after_render_field(record, column); end
209
237
 
@@ -273,11 +301,7 @@ module ActiveScaffold::Actions
273
301
  # Success is the existence of one or more model objects. Most actions
274
302
  # circumvent this method by setting @success directly.
275
303
  def successful?
276
- if @successful.nil?
277
- true
278
- else
279
- @successful
280
- end
304
+ @successful.nil? || @successful
281
305
  end
282
306
 
283
307
  def successful=(val)
@@ -524,11 +548,11 @@ module ActiveScaffold::Actions
524
548
 
525
549
  private
526
550
 
527
- def respond_to_action(action)
551
+ def respond_to_action(action, formats = action_formats)
528
552
  return unless !conditional_get_support? || view_stale?
529
553
 
530
554
  respond_to do |type|
531
- action_formats.each do |format|
555
+ formats.each do |format|
532
556
  type.send(format) do
533
557
  method_name = respond_method_for(action, format)
534
558
  send(method_name) if method_name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold::Actions
2
4
  module Create
3
5
  def self.included(base)
@@ -1,6 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold::Actions
2
4
  module Delete
3
5
  def self.included(base)
6
+ if base.active_scaffold_config.model.primary_key.nil?
7
+ raise "#{base.active_scaffold_config.model.name} has no primary key, delete won't work"
8
+ end
9
+
4
10
  base.before_action :delete_authorized_filter, only: [:destroy]
5
11
  end
6
12