active_scaffold 3.6.0.rc1 → 3.6.0.rc2

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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +10 -0
  3. data/app/assets/javascripts/jquery/active_scaffold.js +47 -13
  4. data/app/assets/stylesheets/active_scaffold_layout.css +1 -1
  5. data/app/views/active_scaffold_overrides/_form_association.html.erb +2 -1
  6. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +4 -2
  7. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +3 -3
  8. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -1
  9. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +2 -2
  10. data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
  11. data/lib/active_scaffold/actions/core.rb +5 -2
  12. data/lib/active_scaffold/actions/nested.rb +1 -1
  13. data/lib/active_scaffold/actions/subform.rb +12 -6
  14. data/lib/active_scaffold/attribute_params.rb +6 -16
  15. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +1 -0
  16. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +4 -4
  17. data/lib/active_scaffold/bridges/paper_trail/actions.rb +3 -1
  18. data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -1
  19. data/lib/active_scaffold/data_structures/association/abstract.rb +1 -4
  20. data/lib/active_scaffold/data_structures/nested_info.rb +12 -0
  21. data/lib/active_scaffold/extensions/cow_proxy.rb +4 -0
  22. data/lib/active_scaffold/finder.rb +7 -5
  23. data/lib/active_scaffold/helpers/controller_helpers.rb +11 -0
  24. data/lib/active_scaffold/helpers/form_column_helpers.rb +50 -13
  25. data/lib/active_scaffold/helpers/list_column_helpers.rb +4 -4
  26. data/lib/active_scaffold/version.rb +1 -1
  27. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c9ea6700cdf564c8c6712df6f538251a00ab77d708a1cb6ddbaf1522f7f3c82
4
- data.tar.gz: c71eb0579b0671fedf08104b51237f260b43ff5d6aa090c98a3ffffde943f31d
3
+ metadata.gz: 482104397cc4bcba59938371add5a7d584a23c3f42aa4b8f3f4ba44f0ffa6114
4
+ data.tar.gz: a140af6343b7a3002740fa8a5af20ddd5da09a0c7a3f384ef31c85a697918cb4
5
5
  SHA512:
6
- metadata.gz: dd0cb52f16d6a75545d491388cbde13f99db60cf0c951db73df00ce77dac5fdd09573331b510fcd2e9a2f637c539e754c8fab0838d5709e22fd8abb11128d9ae
7
- data.tar.gz: b0b4558cf821b84701e42f730eb6699c49a82e3c1e70a6f570d6dd99abbb599f783dded394b94bd7aa96db89d4cd4a23e848480239d4256a5e3f596812ba4e17
6
+ metadata.gz: 89556a2bbb6664fb22291e21bba6108d21c0195788cf5e3fdb6b5d471aab24e7bdef1d40d764f68bb9ecb6e94dfc5c728ac4742b3034a7e74d7e11688933d835
7
+ data.tar.gz: 2606b28e771d97eb6600fb380c34cace3adfbce11cc7baa470de3821dd2bd82e3acec4e66b1bcef14ff7fa17755e2255d7b977a43e85aea893d70d83c2d0f133
@@ -1,3 +1,13 @@
1
+ = 3.6.0.rc2
2
+ - Fix subform crud in subform subgroup when controller is embedded
3
+ - Fix sorting for mongoid models, broken in 3.6.0.rc1
4
+ - Improve add_new option, allow to change subform columns (with helper override calling super and add columns to locals argument)
5
+ - Support add_new option for record_select or radio form_ui
6
+ - Support add_new option for polymorphic associations (add_new may be array with class names to allow add new, or true to allow add new for any model)
7
+ - Support description for columns displayed as subform
8
+ - Don't mess with history if current page is not using activescaffold when is loaded
9
+ - Fix changing sort_by per request when threadsafe is enabled
10
+
1
11
  = 3.6.0.rc1
2
12
  - Cleanup: deprecate ActiveScaffold.set_defaults for ActiveScaffold.defaults, rename some setters
3
13
  - Fix adding new action links on request with threadsafety enabled
@@ -323,20 +323,34 @@ jQuery(document).ready(function($) {
323
323
  if (jQuery(this).prop('checked')) color_field.val('');
324
324
  });
325
325
 
326
- jQuery(document).on('click', '.show-new-subform', function(e) {
327
- e.preventDefault();
326
+ jQuery(document).on('click', '.hide-new-subform, .show-new-subform', function(e) {
328
327
  var $this = jQuery(this), line = $this.closest('.form-element'),
329
- select = line.find('#' + $this.data('select-id')),
330
- subform = line.find('#' + $this.data('subform-id'));
331
- if (select.is(':visible')) {
332
- select.hide().prop('disabled', true);
333
- subform.show().find("input:disabled,select:disabled,textarea:disabled").prop('disabled', false);
334
- $this.data('select-text', $this.html());
335
- $this.html($this.data('subform-text'));
328
+ subform = line.find('#' + $this.data('subform-id')), radio = false, hide, select;
329
+ if ($this.is('[type=radio]')) {
330
+ radio = true;
331
+ hide = $this.is('.hide-new-subform');
336
332
  } else {
333
+ e.preventDefault();
334
+ hide = subform.is(':visible');
335
+ }
336
+ if ($this.data('select-id')) {
337
+ select = line.find('#' + $this.data('select-id'));
338
+ if (select.hasClass('recordselect') || select.is('.no-options')) select = select.next(':hidden').andSelf();
339
+ }
340
+ if (hide) {
337
341
  subform.hide().find("input:enabled,select:enabled,textarea:enabled").prop('disabled', true);
338
- select.show().prop('disabled', false);
339
- $this.html($this.data('select-text'));
342
+ if (select) select.show().prop('disabled', false);
343
+ if (radio) {
344
+ $this.closest('.form-element').find('[name="' + $this.attr('name') + '"].show-new-subform').prop('disabled', false);
345
+ } else $this.html($this.data('select-text'));
346
+ } else {
347
+ if (select) select.hide().prop('disabled', true);
348
+ subform.show().find("input:disabled,select:disabled,textarea:disabled").prop('disabled', false);
349
+ if (radio) $this.prop('disabled', true);
350
+ else {
351
+ $this.data('select-text', $this.html());
352
+ $this.html($this.data('subform-text'));
353
+ }
340
354
  }
341
355
  });
342
356
 
@@ -500,6 +514,7 @@ var ActiveScaffold = {
500
514
  ActiveScaffold.disable_optional_subforms(container);
501
515
  },
502
516
  setup_history_state: function() {
517
+ if (!jQuery('.active-scaffold').length) return;
503
518
  var data = {}, current_search_item = jQuery('.active-scaffold .filtered-message[data-search]');
504
519
  if (current_search_item.length) {
505
520
  // store user settings enabled, update state with current page, search and sorting
@@ -536,8 +551,27 @@ var ActiveScaffold = {
536
551
  jQuery('.as-js-button', element).show();
537
552
  },
538
553
  disable_optional_subforms: function(element) {
539
- jQuery('.form-element select + .sub-form').each(function() {
540
- jQuery("input:enabled,select:enabled,textarea:enabled", this).prop('disabled', true);
554
+ jQuery('.sub-form.optional', element).each(function () {
555
+ var $this = jQuery(this), toggle = $this.find('>.visibility-toggle');
556
+ if (toggle.length) {
557
+ var hide = toggle.text() == toggle.data('show');
558
+ $this.find('> [id] > .sub-form-record > .associated-record dl:first').each(function (i) {
559
+ var parent = jQuery(this).parent(), div_id = toggle.data('toggable') + i;
560
+ parent.children().wrapAll('<div id="' + div_id + '">');
561
+ if (hide) parent.find('> div').hide();
562
+ parent.prepend(toggle.clone().data('toggable', div_id));
563
+ });
564
+ toggle.remove();
565
+ }
566
+ if ($this.is(':visible')) {
567
+ var line = $this.closest('.form-element'), toggle = line.find('.show-new-subform[data-subform-id="' + $this.attr('id') + '"]').first();
568
+ if (toggle.is('[type=radio]')) toggle.prop('disabled', true);
569
+ else if (toggle.data('select-id')) {
570
+ select = line.find('#' + toggle.data('select-id'));
571
+ if (select.hasClass('recordselect') || select.is('.no-options')) select = select.next(':hidden').andSelf();
572
+ select.hide().prop('disabled', true);
573
+ }
574
+ } else $this.find("input:enabled,select:enabled,textarea:enabled").prop('disabled', true);
541
575
  });
542
576
  },
543
577
  sliders: function(element) {
@@ -841,7 +841,7 @@ clear: left;
841
841
  padding: 5px 0;
842
842
  padding-left: 5px;
843
843
  }
844
- .active-scaffold .form-element select + .sub-form {
844
+ .active-scaffold .form-element .sub-form.optional {
845
845
  float: none;
846
846
  }
847
847
  .active-scaffold .form-element .show-new-subform {
@@ -13,8 +13,9 @@ footer = render(:partial => 'form_association_footer', :locals => {:parent_recor
13
13
  -%>
14
14
  <h5>
15
15
  <%= column.label -%>
16
- <%= link_to_visibility_toggle(subform_div_id, {:default_visible => !column.collapsed}) -%>
16
+ <%= link_to_visibility_toggle(subform_div_id, default_visible: !column.collapsed) -%>
17
17
  </h5>
18
+ <%= content_tag :span, column.description, class: 'description' if column.description.present? %>
18
19
  <div id ="<%= subform_div_id %>" <%= 'style="display: none;"'.html_safe if column.collapsed -%>>
19
20
  <%# HACK: to be able to delete all associated records %>
20
21
  <%= hidden_field_tag "#{(opts = active_scaffold_input_options(column, scope, :object => parent_record))[:name]}[0]", '', :id => "#{opts[:id]}_0" if column.association.collection? %>
@@ -6,11 +6,13 @@
6
6
  show_actions = false
7
7
  locked ||= false
8
8
  config = active_scaffold_config_for(record.class)
9
+ columns ||= config.subform.columns
9
10
  scope = column_scope(record_column, scope, record)
10
11
  options = active_scaffold_input_options(config.columns[record.class.primary_key], scope, :object => record)
11
12
  tr_id = "association-#{options[:id]}"
13
+ layout ||= config.subform.layout
12
14
 
13
- if config.subform.layout == :vertical
15
+ if layout == :vertical
14
16
  record_tag ||= :div
15
17
  row_tag ||= :ol
16
18
  column_tag ||= :li
@@ -40,7 +42,7 @@
40
42
  <% end %>
41
43
  <% end %>
42
44
  <%= content_tag row_tag, :id => tr_id, :class => "association-record#{' association-record-new' if record.new_record?}#{' locked' if locked}" do %>
43
- <% config.subform.columns.each_column(for: record.class, crud_type: :read, flatten: flatten) do |column| %>
45
+ <% columns.each_column(for: record.class, crud_type: :read, flatten: flatten) do |column| %>
44
46
  <%
45
47
  if column.respond_to? :each_column
46
48
  columns_groups << column
@@ -2,10 +2,10 @@
2
2
  <%
3
3
  header_record_class = (show_blank_record && show_blank_record.class) || column.association.klass
4
4
  -%>
5
- <%= render :partial => 'horizontal_subform_header', :locals => {:parent_record => parent_record, :record_class => header_record_class, :parent_column => column} %>
5
+ <%= render partial: 'horizontal_subform_header', :locals => {parent_record: parent_record, record_class: header_record_class, parent_column: column, columns: local_assigns[:columns]} %>
6
6
 
7
- <%= render :partial => 'form_association_record', :collection => associated, :locals => {:scope => scope, :parent_record => parent_record, :column => column} %>
8
- <%= render :partial => 'form_association_record', :object => show_blank_record, :locals => {:scope => scope, :parent_record => parent_record, :column => column, :locked => true, :index => associated.size} if show_blank_record %>
7
+ <%= render partial: 'form_association_record', collection: associated, locals: {scope: scope, parent_record: parent_record, column: column, columns: local_assigns[:columns], layout: :horizontal} %>
8
+ <%= render partial: 'form_association_record', object: show_blank_record, locals: {scope: scope, parent_record: parent_record, column: column, columns: local_assigns[:columns], layout: :horizontal, locked: true, index: associated.size} if show_blank_record %>
9
9
  <tfoot>
10
10
  <%= render :partial => 'horizontal_subform_footer', :locals => {:scope => scope, :parent_record => parent_record, :column => column} %>
11
11
  </tfoot>
@@ -1,7 +1,8 @@
1
1
  <thead>
2
2
  <tr>
3
3
  <%
4
- active_scaffold_config_for(record_class).subform.columns.each_column(for: record_class, crud_type: :read) do |column|
4
+ columns ||= active_scaffold_config_for(record_class).subform.columns
5
+ columns.each_column(for: record_class, crud_type: :read) do |column|
5
6
  next unless column.is_a? ActiveScaffold::DataStructures::Column
6
7
  next unless in_subform?(column, parent_record, parent_column)
7
8
  hidden = column_renders_as(column) == :hidden
@@ -1,4 +1,4 @@
1
1
  <div id="<%= sub_form_list_id(:association => column.name, :id => parent_record.id || generated_id(parent_record) || 99999999999) %>">
2
- <%= render :partial => 'form_association_record', :collection => associated, :locals => {:scope => scope, :parent_record => parent_record, :column => column} %>
3
- <%= render :partial => 'form_association_record', :object => show_blank_record, :locals => {:scope => scope, :parent_record => parent_record, :column => column, :locked => true, :index => associated.size} if show_blank_record %>
2
+ <%= render partial: 'form_association_record', collection: associated, locals: {scope: scope, parent_record: parent_record, column: column, columns: local_assigns[:columns], layout: :vertical} %>
3
+ <%= render partial: 'form_association_record', object: show_blank_record, locals: {scope: scope, parent_record: parent_record, column: column, columns: local_assigns[:columns], layout: :vertical, locked: true, index: associated.size} if show_blank_record %>
4
4
  </div>
@@ -22,5 +22,5 @@
22
22
  ActiveScaffold.replace_html('<%= @column_span_id %>','<%= escape_javascript(get_column_value(@record, @column)) %>');
23
23
  <% end -%>
24
24
  <% if @column.calculation? -%>
25
- ActiveScaffold.replace_html('<%= active_scaffold_calculations_id(:column => @column) %>', '<%= escape_javascript(render_column_calculation(@column)) %>');
25
+ ActiveScaffold.replace_html('<%= active_scaffold_calculations_id(:column => @column) %>', '<%= escape_javascript(render_column_calculation(@column, id_condition: false)) %>');
26
26
  <% end -%>
@@ -72,7 +72,8 @@ module ActiveScaffold::Actions
72
72
  else
73
73
  updated_record_with_column(@column, params.delete(:value), @scope)
74
74
  end
75
- setup_parent(@record) if main_form_controller && @scope
75
+ # if @scope has more than 2 ] then it's subform inside subform, and assign parent would fail (found associotion may be through association)
76
+ setup_parent(@record) if main_form_controller && @scope && @scope.scan(']').size == 2
76
77
  after_render_field(@record, @column)
77
78
  end
78
79
 
@@ -277,7 +278,9 @@ module ActiveScaffold::Actions
277
278
 
278
279
  def new_model
279
280
  relation = beginning_of_chain
280
- build_options = sti_nested_build_options(relation.klass) if nested? && nested.plural_association?
281
+ if nested? && nested.plural_association? && nested.match_model?(active_scaffold_config.model)
282
+ build_options = sti_nested_build_options(relation.klass)
283
+ end
281
284
  relation.respond_to?(:build) ? relation.build(build_options || {}) : relation.new
282
285
  end
283
286
 
@@ -90,7 +90,7 @@ module ActiveScaffold::Actions
90
90
 
91
91
  def beginning_of_chain
92
92
  # only if nested is related to current controller, e.g. not when adding record in subform inside subform
93
- if nested? && nested.association && nested.association.klass == active_scaffold_config.model
93
+ if nested? && nested.match_model?(active_scaffold_config.model)
94
94
  nested_chain_with_association
95
95
  elsif nested? && nested.scope
96
96
  nested_parent_record.send(nested.scope)
@@ -9,19 +9,25 @@ module ActiveScaffold::Actions
9
9
 
10
10
  protected
11
11
 
12
- def do_edit_associated
13
- @parent_record = params[:id].nil? ? new_model : find_if_allowed(params[:id], :update)
14
- if @parent_record.new_record?
15
- apply_constraints_to_record @parent_record
16
- create_association_with_parent @parent_record if nested?
12
+ def new_parent_record
13
+ parent_record = new_model
14
+ # don't apply if scope, subform inside subform, because constraints won't apply to parent_record
15
+ apply_constraints_to_record parent_record unless @scope
16
+ if nested? && nested.match_model?(active_scaffold_config.model)
17
+ create_association_with_parent parent_record
17
18
  end
19
+ parent_record
20
+ end
21
+
22
+ def do_edit_associated
23
+ @scope = params[:scope]
24
+ @parent_record = params[:id].nil? ? new_parent_record : find_if_allowed(params[:id], :update)
18
25
 
19
26
  cache_generated_id(@parent_record, params[:generated_id]) if @parent_record.new_record?
20
27
  @column = active_scaffold_config.columns[params[:child_association]]
21
28
 
22
29
  @record = find_associated_record if params[:associated_id]
23
30
  @record ||= build_associated(@column.association, @parent_record)
24
- @scope = params[:scope]
25
31
  end
26
32
 
27
33
  def find_associated_record
@@ -230,7 +230,7 @@ module ActiveScaffold
230
230
  return nil unless build_record_from_params?(attributes, column, parent_record)
231
231
  record = find_or_create_for_params(attributes, column, parent_record)
232
232
  if record
233
- record_columns = active_scaffold_config_for(column.association.klass).subform.columns
233
+ record_columns = active_scaffold_config_for(record.class).subform.columns
234
234
  prev_constraints = record_columns.constraint_columns
235
235
  record_columns.constraint_columns = [column.association.reverse].compact
236
236
  update_record_from_params(record, record_columns, attributes, avoid_changes)
@@ -242,8 +242,9 @@ module ActiveScaffold
242
242
 
243
243
  def build_record_from_params?(params, column, record)
244
244
  current = record.send(column.name)
245
- klass = column.association.klass
246
- (column.association.collection? && !column.show_blank_record?(current)) || !attributes_hash_is_empty?(params, klass)
245
+ return true if column.association.collection? && !column.show_blank_record?(current)
246
+ klass = column.association.klass(record)
247
+ klass && !attributes_hash_is_empty?(params, klass)
247
248
  end
248
249
 
249
250
  # Attempts to create or find an instance of the klass of the association in parent_column from the
@@ -251,12 +252,12 @@ module ActiveScaffold
251
252
  # otherwise it will build a new one.
252
253
  def find_or_create_for_params(params, parent_column, parent_record)
253
254
  current = parent_record.send(parent_column.name)
254
- klass = parent_column.association.klass
255
+ klass = parent_column.association.klass(parent_record)
255
256
  if params.key? klass.primary_key
256
257
  record_from_current_or_find(klass, params[klass.primary_key], current)
257
258
  elsif klass.authorized_for?(:crud_type => :create)
258
259
  association = parent_column.association
259
- record = association.klass.new
260
+ record = klass.new
260
261
  if association.reverse_association&.belongs_to? && (association.collection? || current.nil?)
261
262
  record.send("#{parent_column.association.reverse}=", parent_record)
262
263
  end
@@ -278,17 +279,6 @@ module ActiveScaffold
278
279
  end
279
280
  end
280
281
 
281
- def save_record_to_association(record, association, value, reverse = nil)
282
- return unless association
283
- if association.collection?
284
- record.send(association.name) << value
285
- elsif reverse&.belongs_to?
286
- value.send("#{reverse.name}=", record)
287
- else
288
- record.send("#{association.name}=", value)
289
- end
290
- end
291
-
292
282
  # Determines whether the given attributes hash is "empty".
293
283
  # This isn't a literal emptiness - it's an attempt to discern whether the user intended it to be empty or not.
294
284
  def attributes_hash_is_empty?(hash, klass)
@@ -24,6 +24,7 @@ module ActiveScaffold
24
24
  columns << field
25
25
  columns.exclude "#{field}_attachment#{'s' if field_type == :has_many}".to_sym
26
26
  columns.exclude "#{field}_blob#{'s' if field_type == :has_many}".to_sym
27
+ columns[field].includes ||= ["#{field}_attachment#{'s' if field_type == :has_many}".to_sym, "#{field}_blob#{'s' if field_type == :has_many}".to_sym]
27
28
  columns[field].form_ui ||= "active_storage_#{field_type}".to_sym
28
29
  columns[field].params.add "delete_#{field}"
29
30
  end
@@ -3,7 +3,7 @@ module ActiveScaffold
3
3
  module ListColumnHelpers
4
4
  def active_scaffold_column_active_storage_has_one(record, column)
5
5
  attachment = record.send(column.name.to_s)
6
- attachment.attached? ? link_for_attachment(attachment) : nil
6
+ attachment.attached? ? link_for_attachment(attachment, column) : nil
7
7
  end
8
8
 
9
9
  def active_scaffold_column_active_storage_has_many(record, column)
@@ -12,7 +12,7 @@ module ActiveScaffold
12
12
 
13
13
  attachments = active_storage_files.attachments
14
14
  if attachments.size <= 3 # Lets display up to three links, otherwise just show the count.
15
- links = attachments.map { |attachment| link_for_attachment(attachment) }
15
+ links = attachments.map { |attachment| link_for_attachment(attachment, column) }
16
16
  safe_join links, association_join_text(column)
17
17
  else
18
18
  pluralize attachments.size, column.name.to_s
@@ -21,10 +21,10 @@ module ActiveScaffold
21
21
 
22
22
  private
23
23
 
24
- def link_for_attachment(attachment)
24
+ def link_for_attachment(attachment, column)
25
25
  variant = column.options[:thumb] || ActiveScaffold::Bridges::ActiveStorage::ActiveStorageBridgeHelpers.thumbnail_variant
26
26
  content =
27
- if variant && attachment.variable?
27
+ if variant && attachment.variable? && column.options[:thumb] != false
28
28
  image_tag(attachment.variant(variant))
29
29
  else
30
30
  attachment.filename
@@ -11,7 +11,9 @@ module ActiveScaffold::Actions
11
11
 
12
12
  def deleted
13
13
  query = PaperTrail::Version.destroys.where(:item_type => active_scaffold_config.model)
14
- query = query.where_object(nested.child_association.foreign_key => nested.parent_id) if nested? && nested.child_association.belongs_to? && PaperTrail::Version.respond_to?(:where_object)
14
+ if nested? && nested.child_association&.belongs_to? && PaperTrail::Version.respond_to?(:where_object)
15
+ query = query.where_object(nested.child_association.foreign_key => nested.parent_id)
16
+ end
15
17
  pager = Paginator.new(query.count, active_scaffold_config.list.per_page) do |offset, per_page|
16
18
  query.offset(offset).limit(per_page).map(&:reify)
17
19
  end
@@ -14,7 +14,9 @@ class ActiveScaffold::Bridges::RecordSelect
14
14
  record = options.delete(:object)
15
15
  if column.association&.singular?
16
16
  multiple = column.options.dig(:html_options, :multiple)
17
- active_scaffold_record_select(record, column, options, record.send(column.name), multiple)
17
+ html = active_scaffold_record_select(record, column, options, record.send(column.name), multiple)
18
+ html << active_scaffold_new_record_subform(column, record, options) if column.options[:add_new]
19
+ html
18
20
  elsif column.association&.collection?
19
21
  active_scaffold_record_select(record, column, options, record.send(column.name), true)
20
22
  else
@@ -12,13 +12,10 @@ module ActiveScaffold::DataStructures::Association
12
12
 
13
13
  def klass(record = nil)
14
14
  if polymorphic?
15
- record&.send(foreign_type)&.constantize
15
+ record&.send(foreign_type)&.safe_constantize
16
16
  else
17
17
  @association.klass
18
18
  end
19
- rescue NameError => e
20
- Rails.logger.warn "#{e.message}\n#{e.backtrace.join("\n")}"
21
- nil
22
19
  end
23
20
 
24
21
  def belongs_to?
@@ -66,6 +66,10 @@ module ActiveScaffold::DataStructures
66
66
  def sorted?(*)
67
67
  false
68
68
  end
69
+
70
+ def match_model?(model)
71
+ false
72
+ end
69
73
  end
70
74
 
71
75
  class NestedInfoAssociation < NestedInfo
@@ -100,6 +104,14 @@ module ActiveScaffold::DataStructures
100
104
  association.through?
101
105
  end
102
106
 
107
+ def match_model?(model)
108
+ if association.polymorphic?
109
+ child_association&.inverse_klass == model
110
+ else
111
+ association.klass == model
112
+ end
113
+ end
114
+
103
115
  def sorted?(chain)
104
116
  default_sorting(chain).present?
105
117
  end
@@ -18,6 +18,10 @@ module CowProxy
18
18
  end
19
19
  super
20
20
  end
21
+
22
+ def sort_by(options)
23
+ @sort = options
24
+ end
21
25
  end
22
26
 
23
27
  class Set < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::Set)
@@ -409,9 +409,9 @@ module ActiveScaffold
409
409
  params_hash active_scaffold_embedded_params[:conditions]
410
410
  end
411
411
 
412
- def all_conditions
412
+ def all_conditions(include_id_condition = true)
413
413
  [
414
- id_condition, # for list with id (e.g. /users/:id/index)
414
+ (id_condition if include_id_condition), # for list with id (e.g. /users/:id/index)
415
415
  active_scaffold_conditions, # from the search modules
416
416
  conditions_for_collection, # from the dev
417
417
  conditions_from_params, # from the parameters (e.g. /users/list?first_name=Fred)
@@ -444,9 +444,11 @@ module ActiveScaffold
444
444
  def finder_options(options = {})
445
445
  search_conditions = all_conditions
446
446
 
447
+ sorting = options[:sorting]&.clause((grouped_columns_calculations if grouped_search?))
448
+ sorting = sorting.map(&Arel.method(:sql)) if sorting && active_scaffold_config.active_record?
447
449
  # create a general-use options array that's compatible with Rails finders
448
450
  finder_options = {
449
- :reorder => options[:sorting]&.clause((grouped_columns_calculations if grouped_search?)).map(&Arel.method(:sql)),
451
+ :reorder => sorting,
450
452
  :conditions => search_conditions
451
453
  }
452
454
  if active_scaffold_config.mongoid?
@@ -519,8 +521,8 @@ module ActiveScaffold
519
521
  @last_modified = query.maximum(:updated_at)
520
522
  end
521
523
 
522
- def calculate_query
523
- conditions = all_conditions
524
+ def calculate_query(id_condition = true)
525
+ conditions = all_conditions(id_condition)
524
526
  includes = active_scaffold_config.list.count_includes
525
527
  includes ||= active_scaffold_references if conditions.present?
526
528
  left_joins = active_scaffold_outer_joins
@@ -180,6 +180,17 @@ module ActiveScaffold
180
180
  end
181
181
  end
182
182
  end
183
+
184
+ def save_record_to_association(record, association, value, reverse = nil)
185
+ return unless association
186
+ if association.collection?
187
+ record.association(association.name).target << value
188
+ elsif reverse&.belongs_to?
189
+ value.send("#{reverse.name}=", record)
190
+ else
191
+ record.send("#{association.name}=", value)
192
+ end
193
+ end
183
194
  end
184
195
  end
185
196
  end
@@ -71,9 +71,9 @@ module ActiveScaffold
71
71
  end
72
72
  end
73
73
 
74
- def active_scaffold_subform_attributes(column, column_css_class = nil)
74
+ def active_scaffold_subform_attributes(column, column_css_class = nil, klass = nil)
75
75
  {
76
- :class => "sub-form #{active_scaffold_config_for(column.association.klass).subform.layout}-sub-form #{column_css_class} #{column.name}-sub-form",
76
+ :class => "sub-form #{active_scaffold_config_for(klass || column.association.klass).subform.layout}-sub-form #{column_css_class} #{column.name}-sub-form",
77
77
  :id => sub_form_id(:association => column.name)
78
78
  }
79
79
  end
@@ -308,17 +308,39 @@ module ActiveScaffold
308
308
  html
309
309
  end
310
310
 
311
- def active_scaffold_new_record_subform(column, record, html_options)
312
- subform_attrs = active_scaffold_subform_attributes(column).merge(style: 'display: none')
311
+ def active_scaffold_new_record_subform(column, record, html_options, new_record_attributes: nil, locals: {}, skip_link: false) # rubocop:disable Metrics/ParameterLists
312
+ klass =
313
+ if column.association.polymorphic? && column.association.belongs_to?
314
+ type = record.send(column.association.foreign_type)
315
+ column.association.klass(record) if type.present? && (column.options[:add_new] == true || type.in?(column.options[:add_new]))
316
+ else
317
+ column.association.klass
318
+ end
319
+ return content_tag(:div, '') unless klass
320
+ subform_attrs = active_scaffold_subform_attributes(column, nil, klass)
321
+ if record.send(column.name)&.new_record?
322
+ new_record = record.send(column.name)
323
+ else
324
+ subform_attrs[:style] = 'display: none'
325
+ end
326
+ subform_attrs[:class] << ' optional'
313
327
  scope = html_options[:name].scan(/record(.*)\[#{column.name}\]/).dig(0, 0)
314
- new_record = build_associated(column.association, record)
315
- subform = render(partial: subform_partial_for_column(column), locals: {column: column, parent_record: record, associated: [], show_blank_record: new_record, scope: scope})
328
+ new_record ||= klass.new(new_record_attributes)
329
+ locals = locals.reverse_merge(column: column, parent_record: record, associated: [], show_blank_record: new_record, scope: scope)
330
+ subform = render(partial: subform_partial_for_column(column, klass), locals: locals)
331
+ if column.options[:hide_subgroups]
332
+ toggable_id = "#{sub_form_id(association: column.name, id: record.id || generated_id(record) || 99_999_999_999)}-div"
333
+ subform << link_to_visibility_toggle(toggable_id, default_visible: false)
334
+ end
316
335
  html = content_tag(:div, subform, subform_attrs)
336
+ return html if skip_link
317
337
  html << active_scaffold_show_new_subform_link(column, record, html_options[:id], subform_attrs[:id])
318
338
  end
319
339
 
320
340
  def active_scaffold_show_new_subform_link(column, record, select_id, subform_id)
321
- link_to(as_(:create_new), '#', data: {select_id: select_id, subform_id: subform_id, subform_text: as_(:add_existing)}, class: 'show-new-subform')
341
+ data = {select_id: select_id, subform_id: subform_id, subform_text: as_(:add_existing), select_text: as_(:create_new)}
342
+ label = data[record.send(column.name)&.new_record? ? :subform_text : :select_text]
343
+ link_to(label, '#', data: data, class: 'show-new-subform')
322
344
  end
323
345
 
324
346
  def active_scaffold_file_with_remove_link(column, options, content, remove_file_prefix, controls_class, &block) # rubocop:disable Metrics/ParameterLists
@@ -469,20 +491,35 @@ module ActiveScaffold
469
491
  active_scaffold_enum_options(column, record)
470
492
  end
471
493
 
472
- selected = record.send(column.association.name)&.id if column.association
494
+ selected = record.send(column.association.name) if column.association
495
+ selected_id = selected&.id
473
496
  if options.present?
497
+ if column.options[:add_new]
498
+ html_options[:data] ||= {}
499
+ html_options[:data][:subform_id] = active_scaffold_subform_attributes(column)[:id]
500
+ radio_html_options = html_options.merge(class: html_options[:class] + ' hide-new-subform')
501
+ else
502
+ radio_html_options = html_options
503
+ end
474
504
  radios = options.map do |option|
475
- active_scaffold_radio_option(option, selected, column, html_options)
505
+ active_scaffold_radio_option(option, selected_id, column, radio_html_options)
476
506
  end
477
507
  if column.options[:include_blank]
478
508
  label = column.options[:include_blank]
479
509
  label = as_(column.options[:include_blank]) if column.options[:include_blank].is_a?(Symbol)
480
510
  radios.prepend content_tag(:label, radio_button(:record, column.name, '', html_options.merge(id: nil)) + label)
481
511
  end
512
+ if column.options[:add_new]
513
+ create_new_button = radio_button_tag(html_options[:name], '', selected&.new_record?, html_options.merge(id: nil, class: html_options[:class] + ' show-new-subform'))
514
+ radios << content_tag(:label, create_new_button << as_(:create_new)) <<
515
+ active_scaffold_new_record_subform(column, record, html_options, skip_link: true)
516
+ end
482
517
  safe_join radios
483
518
  else
484
- content_tag(:span, as_(:no_options), :class => "#{html_options[:class]} no-options", :id => html_options[:id]) <<
485
- hidden_field_tag(html_options[:name], '', :id => nil)
519
+ html = content_tag(:span, as_(:no_options), :class => "#{html_options[:class]} no-options", :id => html_options[:id])
520
+ html << hidden_field_tag(html_options[:name], '', :id => nil)
521
+ html << active_scaffold_new_record_subform(column, record, html_options) if column.options[:add_new]
522
+ html
486
523
  end
487
524
  end
488
525
 
@@ -628,8 +665,8 @@ module ActiveScaffold
628
665
  end
629
666
  alias override_input? override_input
630
667
 
631
- def subform_partial_for_column(column)
632
- subform_partial = "#{active_scaffold_config_for(column.association.klass).subform.layout}_subform"
668
+ def subform_partial_for_column(column, klass = nil)
669
+ subform_partial = "#{column.options[:layout] || active_scaffold_config_for(klass || column.association.klass).subform.layout}_subform"
633
670
  override_subform_partial(column, subform_partial) || subform_partial
634
671
  end
635
672
 
@@ -427,16 +427,16 @@ module ActiveScaffold
427
427
 
428
428
  # CALCULATIONS
429
429
 
430
- def column_calculation(column)
430
+ def column_calculation(column, id_condition: true)
431
431
  if column.calculate.instance_of? Proc
432
432
  column.calculate.call(@records)
433
433
  else
434
- calculate_query.calculate(column.calculate, column.name)
434
+ calculate_query(id_condition).calculate(column.calculate, column.name)
435
435
  end
436
436
  end
437
437
 
438
- def render_column_calculation(column)
439
- calculation = column_calculation(column)
438
+ def render_column_calculation(column, id_condition: true)
439
+ calculation = column_calculation(column, id_condition: id_condition)
440
440
  override_formatter = "render_#{column.name}_#{column.calculate.is_a?(Proc) ? :calculate : column.calculate}"
441
441
  calculation = send(override_formatter, calculation) if respond_to? override_formatter
442
442
  format_column_calculation(column, calculation)
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Version
3
3
  MAJOR = 3
4
4
  MINOR = 6
5
- PATCH = '0.rc1'.freeze
5
+ PATCH = '0.rc2'.freeze
6
6
 
7
7
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0.rc1
4
+ version: 3.6.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Many, see README
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2020-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails