diff --git a/lib/activeadmin_table_footer/table_for_extension.rb b/lib/activeadmin_table_footer/table_for_extension.rb index 25956b0..fbfe188 100644 --- a/lib/activeadmin_table_footer/table_for_extension.rb +++ b/lib/activeadmin_table_footer/table_for_extension.rb @@ -8,10 +8,12 @@ def build(obj, *attrs) super(obj, *attrs, options) end + # Any falsy callback means "no footer" — `&.` would only skip nil and raise + # on `footer_data: false`, which is what `footer_data: flag && ->(c) { ... }` + # passes when the flag is off. def footer_data return @footer_data if defined?(@footer_data) - return (@footer_data = nil) unless @footer_data_proc - @footer_data = @footer_data_proc.call(unscoped_collection_for_footer) + @footer_data = (@footer_data_proc.call(unscoped_collection_for_footer) if @footer_data_proc) end # The collection AA passes us is the paginated + ordered slice. Aggregates @@ -49,14 +51,15 @@ def column_has_footer?(col) def build_footer_cell_for(col) within @aatf_footer_row do column_key = column_key_for(col) - # Always include `col col-` so capybara_active_admin matchers - # (`have_table_cell(column: ...)`) work in both AA 3 and AA 4 — the - # selector convention is `td.col.col-`. - compat_classes = column_key ? "col col-#{column_key}" : "col" - classes = [col.html_class, compat_classes, ActiveadminTableFooter.footer_th_class] - .reject { |c| c.nil? || c.to_s.empty? } - .join(" ") - attrs = { class: classes.empty? ? nil : classes } + # `col` + `col-` keeps capybara_active_admin's + # `have_table_cell(column: ...)` matcher working on AA 3 and AA 4. + classes = [ + col.html_class, + "col", + ("col-#{column_key}" if column_key), + ActiveadminTableFooter.footer_th_class + ].compact_blank.join(" ").presence + attrs = { class: classes } attrs[:"data-column"] = column_key if column_key td(**attrs) do render_footer_value(col) if column_has_footer?(col) @@ -66,12 +69,8 @@ def build_footer_cell_for(col) def column_key_for(col) # AA 4 exposes Column#title_id; AA 3 does not — derive from title. - if col.respond_to?(:title_id) && col.title_id.respond_to?(:presence) - return col.title_id.presence - end - title = col.title.to_s - return nil if title.empty? - title.parameterize(separator: "_") + return col.title_id.presence if col.respond_to?(:title_id) + col.title.to_s.presence&.parameterize(separator: "_") end def ensure_tfoot! diff --git a/spec/unit/table_for_extension_spec.rb b/spec/unit/table_for_extension_spec.rb index b059498..001e1e4 100644 --- a/spec/unit/table_for_extension_spec.rb +++ b/spec/unit/table_for_extension_spec.rb @@ -12,4 +12,23 @@ expect(ActiveAdmin::Views::TableFor.instance_method(:footer_data)).to be_a(UnboundMethod) end end + + # `table_for items, footer_data: show_totals && ->(c) { ... }` passes `false` + # when the flag is off. A falsy callback means "no footer", same as the index + # wrapper already assumes (`footer_proc && page_presenter.block`). + describe "#footer_data with a falsy callback" do + let(:table) { ActiveAdmin::Views::TableFor.allocate } + + it "treats false as no callback instead of raising" do + table.instance_variable_set(:@footer_data_proc, false) + + expect(table.footer_data).to be_nil + end + + it "treats nil as no callback" do + table.instance_variable_set(:@footer_data_proc, nil) + + expect(table.footer_data).to be_nil + end + end end