Skip to content

Commit 0dabaed

Browse files
authored
[Bug Fix] Fix DataTable pagination with array params and adapter naming (#359)
* Fix build_query losing array param values on sort/paginate Array#to_s returns inspect output (e.g. '["uuid"]'), which Rails re-parses as a literal string inside the array. Use Array(v) to handle both scalar and array values correctly. * Move pagination adapters into data_table/ and rename to avoid conflicts Rename DataTablePaginationAdapters::{Pagy,Kaminari,Manual} to DataTable{Pagy,Kaminari,Manual}Adapter under RubyUI namespace. Fixes class name collision when host app includes RubyUI module (e.g. Pagy clashing with the pagy gem). Also fixes generator only copying data_table/ folder, missing the separate adapters dir. * Add customizable prev/next labels and hide pagination for single page Add prev_label and next_label params (default "<" and ">"). Skip rendering when total pages <= 1. * Remove unnecessary plain calls for label ivars in pagination Phlex renders ivars directly in tag blocks without plain.
1 parent e9679c1 commit 0dabaed

11 files changed

Lines changed: 83 additions & 81 deletions
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module RubyUI
4+
class DataTableKaminariAdapter
5+
def initialize(collection)
6+
@collection = collection
7+
end
8+
9+
def current_page = @collection.current_page
10+
11+
def total_pages = @collection.total_pages
12+
13+
def total_count = @collection.total_count
14+
15+
def per_page = @collection.limit_value
16+
end
17+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module RubyUI
4+
class DataTableManualAdapter
5+
attr_reader :current_page, :per_page, :total_count
6+
7+
def initialize(page:, per_page:, total_count:)
8+
@current_page = page.to_i
9+
@per_page = [per_page.to_i, 1].max
10+
@total_count = total_count.to_i
11+
end
12+
13+
def total_pages
14+
[(@total_count.to_f / @per_page).ceil, 1].max
15+
end
16+
end
17+
end

lib/ruby_ui/data_table/data_table_pagination.rb

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
# frozen_string_literal: true
22

33
require "cgi"
4-
require_relative "../data_table_pagination_adapters/manual"
5-
require_relative "../data_table_pagination_adapters/pagy"
6-
require_relative "../data_table_pagination_adapters/kaminari"
4+
require_relative "data_table_manual_adapter"
5+
require_relative "data_table_pagy_adapter"
6+
require_relative "data_table_kaminari_adapter"
77

88
module RubyUI
99
class DataTablePagination < Base
10-
def initialize(with: nil, pagy: nil, kaminari: nil, page: nil, per_page: nil, total_count: nil, page_param: "page", path: "", query: {}, window: 1, **attrs)
10+
def initialize(with: nil, pagy: nil, kaminari: nil, page: nil, per_page: nil, total_count: nil, page_param: "page", path: "", query: {}, window: 1, prev_label: "<", next_label: ">", **attrs)
1111
@adapter = resolve_adapter(with:, pagy:, kaminari:, page:, per_page:, total_count:)
1212
@page_param = page_param
1313
@path = path
1414
@query = query.to_h.transform_keys(&:to_s)
1515
@window = window
16+
@prev_label = prev_label
17+
@next_label = next_label
1618
super(**attrs)
1719
end
1820

1921
def view_template
22+
return if total <= 1
23+
2024
render RubyUI::Pagination.new(class: "mx-0 w-auto justify-end", **attrs) do
2125
render RubyUI::PaginationContent.new do
2226
prev_item
@@ -30,10 +34,10 @@ def view_template
3034

3135
def resolve_adapter(with:, pagy:, kaminari:, page:, per_page:, total_count:)
3236
return with if with
33-
return RubyUI::DataTablePaginationAdapters::Pagy.new(pagy) if pagy
34-
return RubyUI::DataTablePaginationAdapters::Kaminari.new(kaminari) if kaminari
37+
return RubyUI::DataTablePagyAdapter.new(pagy) if pagy
38+
return RubyUI::DataTableKaminariAdapter.new(kaminari) if kaminari
3539
if page && per_page && total_count
36-
return RubyUI::DataTablePaginationAdapters::Manual.new(page:, per_page:, total_count:)
40+
return RubyUI::DataTableManualAdapter.new(page:, per_page:, total_count:)
3741
end
3842
raise ArgumentError, "DataTablePagination requires one of: with:, pagy:, kaminari:, or page:+per_page:+total_count:"
3943
end
@@ -48,26 +52,28 @@ def page_href(p)
4852
end
4953

5054
def build_query(hash)
51-
hash.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
55+
hash.flat_map { |k, v|
56+
Array(v).map { |val| "#{CGI.escape(k.to_s)}=#{CGI.escape(val.to_s)}" }
57+
}.join("&")
5258
end
5359

5460
def prev_item
5561
if current <= 1
5662
li do
57-
span(class: "opacity-50 pointer-events-none px-3 h-9 inline-flex items-center text-sm") { plain "Previous" }
63+
span(class: "opacity-50 pointer-events-none px-3 h-9 inline-flex items-center text-sm") { @prev_label }
5864
end
5965
else
60-
render RubyUI::PaginationItem.new(href: page_href(current - 1)) { plain "Previous" }
66+
render RubyUI::PaginationItem.new(href: page_href(current - 1)) { @prev_label }
6167
end
6268
end
6369

6470
def next_item
6571
if current >= total
6672
li do
67-
span(class: "opacity-50 pointer-events-none px-3 h-9 inline-flex items-center text-sm") { plain "Next" }
73+
span(class: "opacity-50 pointer-events-none px-3 h-9 inline-flex items-center text-sm") { @next_label }
6874
end
6975
else
70-
render RubyUI::PaginationItem.new(href: page_href(current + 1)) { plain "Next" }
76+
render RubyUI::PaginationItem.new(href: page_href(current + 1)) { @next_label }
7177
end
7278
end
7379

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module RubyUI
4+
class DataTablePagyAdapter
5+
def initialize(pagy)
6+
@pagy = pagy
7+
end
8+
9+
def current_page = @pagy.page
10+
11+
def total_pages = @pagy.pages
12+
13+
def total_count = @pagy.count
14+
15+
def per_page = @pagy.items
16+
end
17+
end

lib/ruby_ui/data_table/data_table_sort_head.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def sort_href
4444
end
4545

4646
def build_query(hash)
47-
hash.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
47+
hash.flat_map { |k, v|
48+
Array(v).map { |val| "#{CGI.escape(k.to_s)}=#{CGI.escape(val.to_s)}" }
49+
}.join("&")
4850
end
4951

5052
def sort_icon

lib/ruby_ui/data_table_pagination_adapters/kaminari.rb

Lines changed: 0 additions & 19 deletions
This file was deleted.

lib/ruby_ui/data_table_pagination_adapters/manual.rb

Lines changed: 0 additions & 19 deletions
This file was deleted.

lib/ruby_ui/data_table_pagination_adapters/pagy.rb

Lines changed: 0 additions & 19 deletions
This file was deleted.

test/ruby_ui/data_table_pagination_adapters/kaminari_test.rb renamed to test/ruby_ui/data_table_kaminari_adapter_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# frozen_string_literal: true
22

33
require "test_helper"
4-
require "ruby_ui/data_table_pagination_adapters/kaminari"
4+
require "ruby_ui/data_table/data_table_kaminari_adapter"
55

6-
class RubyUI::DataTablePaginationAdapters::KaminariTest < ComponentTest
6+
class RubyUI::DataTableKaminariAdapterTest < ComponentTest
77
CollectionDouble = Data.define(:current_page, :total_pages, :total_count, :limit_value)
88

99
def test_reads_current_page_total_pages_total_count_limit_value
1010
coll = CollectionDouble.new(current_page: 3, total_pages: 7, total_count: 61, limit_value: 10)
11-
adapter = RubyUI::DataTablePaginationAdapters::Kaminari.new(coll)
11+
adapter = RubyUI::DataTableKaminariAdapter.new(coll)
1212
assert_equal 3, adapter.current_page
1313
assert_equal 7, adapter.total_pages
1414
assert_equal 61, adapter.total_count

test/ruby_ui/data_table_pagination_adapters/manual_test.rb renamed to test/ruby_ui/data_table_manual_adapter_test.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
# frozen_string_literal: true
22

33
require "test_helper"
4-
require "ruby_ui/data_table_pagination_adapters/manual"
4+
require "ruby_ui/data_table/data_table_manual_adapter"
55

6-
class RubyUI::DataTablePaginationAdapters::ManualTest < ComponentTest
6+
class RubyUI::DataTableManualAdapterTest < ComponentTest
77
def test_computes_total_pages_from_total_count_and_per_page
8-
adapter = RubyUI::DataTablePaginationAdapters::Manual.new(page: 2, per_page: 10, total_count: 25)
8+
adapter = RubyUI::DataTableManualAdapter.new(page: 2, per_page: 10, total_count: 25)
99
assert_equal 2, adapter.current_page
1010
assert_equal 10, adapter.per_page
1111
assert_equal 25, adapter.total_count
1212
assert_equal 3, adapter.total_pages
1313
end
1414

1515
def test_total_pages_is_at_least_1_for_empty_total
16-
adapter = RubyUI::DataTablePaginationAdapters::Manual.new(page: 1, per_page: 10, total_count: 0)
16+
adapter = RubyUI::DataTableManualAdapter.new(page: 1, per_page: 10, total_count: 0)
1717
assert_equal 1, adapter.total_pages
1818
end
1919

2020
def test_coerces_integer_inputs
21-
adapter = RubyUI::DataTablePaginationAdapters::Manual.new(page: "3", per_page: "5", total_count: "12")
21+
adapter = RubyUI::DataTableManualAdapter.new(page: "3", per_page: "5", total_count: "12")
2222
assert_equal 3, adapter.current_page
2323
assert_equal 3, adapter.total_pages
2424
end

0 commit comments

Comments
 (0)