trk_datatables 0.2.8 → 0.2.13
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|