trk_datatables 0.2.8 → 0.2.13
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +179 -6
- data/lib/trk_datatables/active_record.rb +7 -4
- data/lib/trk_datatables/base.rb +1 -4
- data/lib/trk_datatables/base_helpers.rb +2 -2
- data/lib/trk_datatables/column_key_options.rb +6 -1
- data/lib/trk_datatables/dt_params.rb +1 -1
- data/lib/trk_datatables/render_html.rb +2 -1
- data/lib/trk_datatables/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfebccd40ad802ae6e7e6beb1eebec9099f9ede5bf4ed4d2f6f9ed92a08a8f03
|
4
|
+
data.tar.gz: 0fcb0efd54b898d2d2aa68ff76c095293fa0b57abb48a37bd893aa59a676ff4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa204f488a45f055b602e9baf8504cd64e8a91404a69800588065fcabbfa5a85ce2ae9220751fdf7633facdfe1627a98bae33354eabfaf6c64e9053f20f6472a
|
7
|
+
data.tar.gz: ba2fbe421642ed72bff9e023b541c4321c56baa653f54f1ac372d3e7d43233691a7316040340ff20c94e1d4fab6ceb5ce314fe0efeadfa65240e2dee2042593e
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -256,7 +256,7 @@ For specific columns you can use following keys
|
|
256
256
|
* `order: false` disable ordering for this column
|
257
257
|
* `select_options: Post.statuses` generate select box instead of text input
|
258
258
|
* `predefined_ranges: {}` for datetime fiels add ranges to pick up from
|
259
|
-
* `hide: true` hide column with display none
|
259
|
+
* `hide: true` hide column with display none, for example `{ hide: @view.params[:user_id].present? }`
|
260
260
|
* `class_name: 'Admin::User'` use different class name than
|
261
261
|
`table_name.classify` (in this case of `admin_users` will be `AdminUser`)
|
262
262
|
* `column_type_in_db` one of the: `:string`, `:integer`, `:date`, `:datetime`,
|
@@ -332,7 +332,7 @@ def columns
|
|
332
332
|
end
|
333
333
|
|
334
334
|
# in view
|
335
|
-
link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status'
|
335
|
+
link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status',
|
336
336
|
Post.statues.values_at(:published, :promoted)))
|
337
337
|
```
|
338
338
|
|
@@ -531,6 +531,94 @@ class MostLikedPostsDatatable < TrkDatatables::ActiveRecord
|
|
531
531
|
end
|
532
532
|
```
|
533
533
|
|
534
|
+
### Table less models
|
535
|
+
|
536
|
+
You can use raw sql to fetch the data and use it as a model.
|
537
|
+
Here is an example when there is no relations to other models
|
538
|
+
```
|
539
|
+
# app/models/table_less.rb
|
540
|
+
class TableLess < ApplicationRecord
|
541
|
+
self.abstract_class = true
|
542
|
+
|
543
|
+
def self.load_schema!
|
544
|
+
@columns_hash ||= {}
|
545
|
+
|
546
|
+
# From active_record/attributes.rb
|
547
|
+
attributes_to_define_after_schema_loads.each do |name, (type, options)|
|
548
|
+
type = ActiveRecord::Type.lookup(type, **options.except(:default)) if type.is_a?(Symbol)
|
549
|
+
|
550
|
+
define_attribute(name, type, **options.slice(:default))
|
551
|
+
|
552
|
+
# Improve Model#inspect output
|
553
|
+
@columns_hash[name.to_s] = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default])
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
```
|
558
|
+
|
559
|
+
```
|
560
|
+
# app/models/translation.rb
|
561
|
+
class Translation < TableLess
|
562
|
+
self.table_name = :translations
|
563
|
+
|
564
|
+
attribute :translateable_type, :string, default: nil
|
565
|
+
attribute :translateable_id, :string, default: nil
|
566
|
+
attribute :column_name, :string, default: nil
|
567
|
+
attribute :column_value, :string, default: nil
|
568
|
+
|
569
|
+
belongs_to :translateable, polymorphic: true
|
570
|
+
end
|
571
|
+
```
|
572
|
+
|
573
|
+
```
|
574
|
+
# app/datatables/translations_datatable.rb
|
575
|
+
# rubocop:disable Layout/LineLength
|
576
|
+
class TranslationsDatatable < BaseDatatable
|
577
|
+
def columns
|
578
|
+
{
|
579
|
+
'translations.translateable_id': {},
|
580
|
+
'translations.translateable_type': {hide: true},
|
581
|
+
'translations.column_name': {},
|
582
|
+
'translations.column_value': {},
|
583
|
+
'': {},
|
584
|
+
}
|
585
|
+
end
|
586
|
+
|
587
|
+
def all_items
|
588
|
+
sql = <<~SQL.squish
|
589
|
+
(
|
590
|
+
(SELECT 'Activity' AS translateable_type, id AS translateable_id, 'name' AS column_name, name AS column_value FROM activities)
|
591
|
+
UNION
|
592
|
+
(SELECT 'Activity' AS translateable_type, id AS translateable_id, 'description' AS column_name, description AS column_value FROM activities)
|
593
|
+
) as translations
|
594
|
+
SQL
|
595
|
+
Translation.from([Arel.sql(sql)])
|
596
|
+
end
|
597
|
+
|
598
|
+
def rows(filtered)
|
599
|
+
filtered.map do |translation|
|
600
|
+
edit_link = @view.button_tag_open_modal(
|
601
|
+
@view.edit_translation_path(translation.translateable_id, translateable_type: translation.translateable_type, column_name: translation.column_name), title: @view.t_crud('edit', Translation)
|
602
|
+
)
|
603
|
+
[
|
604
|
+
@view.link_to(translation.translateable, translation.translateable),
|
605
|
+
translation.translateable_type,
|
606
|
+
translation.column_name,
|
607
|
+
translation.column_value,
|
608
|
+
edit_link,
|
609
|
+
]
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
# rubocop:enable Layout/LineLength
|
614
|
+
```
|
615
|
+
|
616
|
+
For column title we use `table_class.human_attribute_name column_name`. When
|
617
|
+
calculated_ columns is used than it can not find translation so better is to:
|
618
|
+
```
|
619
|
+
'string_calculated_in_db.column_value_translated': {search: false, title: @view.t('activerecord.attributes.translation.column_value_translated')},
|
620
|
+
```
|
621
|
+
|
534
622
|
### Default order and page length
|
535
623
|
|
536
624
|
You can override default order (index and direction) and default page length so
|
@@ -552,12 +640,41 @@ class PostsDatatable
|
|
552
640
|
end
|
553
641
|
```
|
554
642
|
|
643
|
+
### Render html with additional css class and different DOM
|
644
|
+
|
645
|
+
To add additional styling to your datatable you can use `:class` option when you
|
646
|
+
are calling `@datatable.render_html url, options` for example
|
647
|
+
|
648
|
+
```
|
649
|
+
<%= @datatable.render_html search_posts_path(format: :json), class: 'table-hover' %>
|
650
|
+
```
|
651
|
+
|
652
|
+
Default [DOM](https://datatables.net/reference/option/dom) is
|
653
|
+
`<"trk-global-search-wrapper"f>rtp<"trk-move-up"il>` which includes global
|
654
|
+
**f**iltering, p**r**ocessing loader, **t**able search, **p**agination, table
|
655
|
+
**i**nformation and **l**ength changing control. To override you can use
|
656
|
+
|
657
|
+
```
|
658
|
+
<%= @datatable.render_html search_posts_path(format: :json), 'data-datatable-dom': 'rt' %>
|
659
|
+
```
|
660
|
+
|
555
661
|
### Params
|
556
662
|
|
557
663
|
To set parameters that you can use for links to set column search value, use
|
558
664
|
this `PostsDatatable.param_set 'users.email', 'my@email.com'`. For between
|
559
665
|
search you can use range `Time.zone.today..(Time.zone.today + 1.year)` and for
|
560
|
-
in multiple values use array `[Post.statuses[:draft]]`.
|
666
|
+
in multiple values use array `[Post.statuses[:draft]]`. Note that in Rails
|
667
|
+
`Time.zone.now.to_s` usually returns seconds ('23:59:59') but if you change
|
668
|
+
default format like in `config/initializers/time_formats.rb` with
|
669
|
+
`Time::DATE_FORMATS[:default] = '%d-%b-%Y %I:%M %p'` than range
|
670
|
+
`Time.zone.now.at_beginning_of_day..Time.zone.now.at_end_of_day` will not
|
671
|
+
include those at end of day since param will not include seconds ('23:59') so in
|
672
|
+
this case you can use range for strings
|
673
|
+
`Time.zone.now.at_beginning_of_day.to_s..Time.zone.now.at_end_of_day.to_s(:with_seconds)`
|
674
|
+
and config/initializers/time_formats.rb `Time::DATE_FORMATS[:with_seconds] = '%d-%b-%Y %I:%M:%S %p'`
|
675
|
+
|
676
|
+
(or use date `Time.zone.today..Time.zone.today` but that will not populate
|
677
|
+
datetime fields in dateRangePicker correctly)
|
561
678
|
|
562
679
|
```
|
563
680
|
<%= link_to 'Active posts for my@email.com', \
|
@@ -573,6 +690,15 @@ in multiple values use array `[Post.statuses[:draft]]`.
|
|
573
690
|
This will fill proper column search values so you do not need to do it manually
|
574
691
|
(`post_path(:columns=>{"3"=>{:search=>{:value=>"my@email.com"}},
|
575
692
|
"2"=>{:search=>{:value=>"1|2"}}}, :user_id=>1)`)
|
693
|
+
Please note that user_id is not inside datatable params so it will not be used
|
694
|
+
for next search params (all other search params are used with Datatables and
|
695
|
+
will remain on next search) so you need to manually add that param
|
696
|
+
```
|
697
|
+
<%= @datatable.render_html search_posts_path(user_id: params[:user_id], format: :json) %>
|
698
|
+
```
|
699
|
+
|
700
|
+
You can use generic name `params[:non_table_filter]` and split with colon
|
701
|
+
`user_id:123` but that is not needed.
|
576
702
|
|
577
703
|
For form fields you can use similar helper that will return name which points to
|
578
704
|
specific column, for example:
|
@@ -596,10 +722,39 @@ For global search you can use `[search][value]` for example
|
|
596
722
|
<% end %>
|
597
723
|
```
|
598
724
|
|
599
|
-
If you need, you can fetch params with this helper
|
725
|
+
If you need, you can fetch params with this helper and for example, show the
|
726
|
+
link for that record
|
600
727
|
|
601
728
|
```
|
602
|
-
|
729
|
+
if @datatable.param_get("locations.name").present? &&
|
730
|
+
(location = Location.find_by(name: @datatable.param_get("locations.name")))
|
731
|
+
page_description "For <a href='#{location_path(location)}'>#{location.name}</a>"
|
732
|
+
breadcrumb "Dashboard": dashboard_path, location.name => location_path(location), "Package Sales": nil
|
733
|
+
else
|
734
|
+
breadcrumb "Dashboard": dashboard_path, "Package Sales": nil
|
735
|
+
end
|
736
|
+
```
|
737
|
+
|
738
|
+
For other filter params which are not in columns you can use non table params
|
739
|
+
```
|
740
|
+
# on dashboard
|
741
|
+
<%= link_to 'Locations', isp_locations_path(non_table_filter: "reseller_operator_id:#{@reseller_operator.id}") %>
|
742
|
+
|
743
|
+
# on index
|
744
|
+
if params[:non_table_filter].present? &&
|
745
|
+
(reseller_operator = ResellerOperator.find(params[:non_table_filter].split(":").second))
|
746
|
+
page_description "For <a href='#{reseller_operator_path(reseller_operator)}'>#{reseller_operator.company_name}</a>"
|
747
|
+
breadcrumb 'Dashboard' => isp_dashboard_path, reseller_operator.company_name => reseller_operator_path(reseller_operator), 'Locations' => nil
|
748
|
+
else
|
749
|
+
breadcrumb 'Dashboard' => isp_dashboard_path, 'Locations' => nil
|
750
|
+
end
|
751
|
+
|
752
|
+
# in datatables
|
753
|
+
case @view.params[:non_table_filter].to_s.split(':').first
|
754
|
+
when 'reseller_operator_id'
|
755
|
+
reseller_operator = ResellerOperator.find @view.params[:non_table_filter].split(':').second
|
756
|
+
all_isp_locations = all_isp_locations.where(reseller_operator: reseller_operator)
|
757
|
+
end
|
603
758
|
```
|
604
759
|
|
605
760
|
You can set filters on datatable even params are blank, for example
|
@@ -661,7 +816,9 @@ end
|
|
661
816
|
|
662
817
|
You can use condition to provide different data, for example let's assume
|
663
818
|
`@view.api_user?` returns true for json requests from mobile app. Here is
|
664
|
-
example that provides different columns for normal and api_user
|
819
|
+
example that provides different columns for normal and api_user.
|
820
|
+
Note that when you are using different columns for some reason in `@view` you
|
821
|
+
need to provide view in `param_set` so it can check the same conditionals.
|
665
822
|
|
666
823
|
```
|
667
824
|
# app/datatables/posts_datatable.rb
|
@@ -671,8 +828,14 @@ class PostsDatatable < TrkDatatables::ActiveRecord
|
|
671
828
|
end
|
672
829
|
|
673
830
|
def columns_for_html
|
831
|
+
balance = @view.current_location
|
832
|
+
{}
|
833
|
+
else
|
834
|
+
{ 'integer_calculated_in_db.balance_amount_in_cents': { search: false, title: 'Balance' } }
|
835
|
+
end
|
674
836
|
{
|
675
837
|
'subscribers.subscriberid': {},
|
838
|
+
**balance,
|
676
839
|
'subscribers.name': {},
|
677
840
|
}
|
678
841
|
end
|
@@ -691,8 +854,14 @@ class PostsDatatable < TrkDatatables::ActiveRecord
|
|
691
854
|
|
692
855
|
def rows_for_html(filtered)
|
693
856
|
filtered.map do |subscriber|
|
857
|
+
balance = if Constant.STILL_WITH_OLD_CODE
|
858
|
+
[]
|
859
|
+
else
|
860
|
+
[@view.humanized_money_with_symbol(Money.new(location.balance_amount_in_cents)) : 'NA']
|
861
|
+
end
|
694
862
|
[
|
695
863
|
@view.link_to(subscriber.subscriberid, subscriber),
|
864
|
+
*balance,
|
696
865
|
subscriber.name,
|
697
866
|
]
|
698
867
|
end
|
@@ -712,6 +881,10 @@ class PostsDatatable < TrkDatatables::ActiveRecord
|
|
712
881
|
@view.api_user? ? columns_for_api : nil
|
713
882
|
end
|
714
883
|
end
|
884
|
+
|
885
|
+
# On some dashboard page provide @view using `self` to param_set
|
886
|
+
link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status',
|
887
|
+
:active, self))
|
715
888
|
```
|
716
889
|
|
717
890
|
## Test your datatables
|
@@ -87,12 +87,15 @@ module TrkDatatables
|
|
87
87
|
# we do not need to cast from string since range will do automatically
|
88
88
|
parsed_from = from
|
89
89
|
parsed_to = to
|
90
|
-
when :date
|
90
|
+
when :date
|
91
|
+
parsed_from = _parse_in_zone(from).to_date
|
92
|
+
parsed_to = _parse_in_zone(to).to_date
|
93
|
+
when :datetime
|
91
94
|
parsed_from = _parse_in_zone(from)
|
92
95
|
parsed_to = _parse_in_zone(to)
|
93
|
-
if parsed_to.present? && !to.match(
|
94
|
-
#
|
95
|
-
parsed_to
|
96
|
+
if parsed_to.present? && !to.match(/:/)
|
97
|
+
# Use end of a day if time is not defined, for example 2020-02-02
|
98
|
+
parsed_to = parsed_to.at_end_of_day
|
96
99
|
end
|
97
100
|
end
|
98
101
|
[parsed_from, parsed_to]
|
data/lib/trk_datatables/base.rb
CHANGED
@@ -241,10 +241,7 @@ module TrkDatatables
|
|
241
241
|
'Last Month':
|
242
242
|
Time.zone.today.prev_month.beginning_of_month.beginning_of_day...Time.zone.today.prev_month.end_of_month.end_of_day,
|
243
243
|
'This Year': Time.zone.today.beginning_of_year.beginning_of_day...Time.zone.today.end_of_day,
|
244
|
-
}
|
245
|
-
# datepicker expects format 2020-11-29 11:59:59
|
246
|
-
range.first.strftime('%F %T')..range.last.strftime('%F %T')
|
247
|
-
end
|
244
|
+
}
|
248
245
|
end
|
249
246
|
end
|
250
247
|
end
|
@@ -13,8 +13,8 @@ module TrkDatatables
|
|
13
13
|
# @example
|
14
14
|
# link_to 'Published posts for user1',
|
15
15
|
# posts_path(PostsDatatable.param_set('posts.status', :published).merge(user_id: user1.id))
|
16
|
-
def param_set(column_key, value)
|
17
|
-
datatable = new OpenStruct.new(params: {})
|
16
|
+
def param_set(column_key, value, view = nil)
|
17
|
+
datatable = new view || OpenStruct.new(params: {})
|
18
18
|
value = value.join MULTIPLE_OPTION_SEPARATOR if value.is_a? Array
|
19
19
|
value = [value.first, value.last].join BETWEEN_SEPARATOR if value.is_a? Range
|
20
20
|
column_index = datatable.index_by_column_key column_key
|
@@ -172,7 +172,12 @@ module TrkDatatables
|
|
172
172
|
# This is helper
|
173
173
|
def _determine_string_type_cast # :nodoc:
|
174
174
|
if defined?(::ActiveRecord::Base)
|
175
|
-
|
175
|
+
current_adapter = if ::ActiveRecord::Base.respond_to?(:connection_db_config)
|
176
|
+
::ActiveRecord::Base.connection_db_config.configuration_hash[:adapter]
|
177
|
+
else
|
178
|
+
::ActiveRecord::Base.connection_config[:adapter]
|
179
|
+
end
|
180
|
+
DB_ADAPTER_STRING_TYPE_CAST[current_adapter.to_sym]
|
176
181
|
else
|
177
182
|
'not_used'
|
178
183
|
end
|
@@ -117,7 +117,7 @@ module TrkDatatables
|
|
117
117
|
def param_get(column_index)
|
118
118
|
@params.dig :columns, column_index.to_s, :search, :value
|
119
119
|
rescue TypeError => e
|
120
|
-
raise Error, e.message
|
120
|
+
raise Error, "#{e.message}. Column search is in a format: { \"columns\": { \"0\": { \"search\": { \"value\": { \"ABC\" } } } } }"
|
121
121
|
end
|
122
122
|
|
123
123
|
def self.sample_view_params(options = {})
|
@@ -4,7 +4,7 @@ module TrkDatatables
|
|
4
4
|
def initialize(search_link, datatable, html_options = {})
|
5
5
|
@search_link = search_link
|
6
6
|
@datatable = datatable
|
7
|
-
@html_options = html_options
|
7
|
+
@html_options = html_options.symbolize_keys
|
8
8
|
self.class.indent = 0
|
9
9
|
end
|
10
10
|
|
@@ -89,6 +89,7 @@ module TrkDatatables
|
|
89
89
|
# for initial page load we do not have ability to show recordsTotal
|
90
90
|
# https://github.com/trkin/trk_datatables_js/issues/1
|
91
91
|
'data-datatable-total-length': @datatable.filtered_items_count,
|
92
|
+
'data-datatable-dom': @html_options[:'data-datatable-dom'] || '<"trk-global-search-wrapper"f>rtp<"trk-move-up"il>',
|
92
93
|
) do
|
93
94
|
thead << "\n".html_safe << tbody
|
94
95
|
end +
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trk_datatables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dusan Orlovic
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
220
|
- !ruby/object:Gem::Version
|
221
221
|
version: '0'
|
222
222
|
requirements: []
|
223
|
-
rubygems_version: 3.
|
223
|
+
rubygems_version: 3.2.15
|
224
224
|
signing_key:
|
225
225
|
specification_version: 4
|
226
226
|
summary: Gem that simplify using datatables with Ruby on Rails and Sinatra.
|