query_report 1.0.23 → 1.0.24
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/README.md +46 -10
- data/app/views/query_report/_records.html.erb +1 -1
- data/lib/query_report/column.rb +57 -12
- data/lib/query_report/filter.rb +43 -30
- data/lib/query_report/helper.rb +5 -7
- data/lib/query_report/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38e6dd09227f6ad51d81593b879ded5928ab3c27
|
4
|
+
data.tar.gz: 72ef9413da84d9e5d0f5f802c5b7dd8e4cd4aba0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aad743d74172a389cc058f6354d819b7e1263fcea268bffcecd1c4d3a2928e38c1b02563cc8f75ff2571472300ee7a2709669cd42cc02d7a8963534599a611d3
|
7
|
+
data.tar.gz: 8d5c76e9381b2df6a078f133a82d02ac459f483e93c7afa9281011a58eceb4e50fe800e33ce5add15a104a01c7f2e3da909188ae2fe5e55431c22044f1ecb209
|
data/README.md
CHANGED
@@ -2,14 +2,50 @@
|
|
2
2
|
|
3
3
|
[](http://travis-ci.org/ashrafuzzaman/query_report)
|
4
4
|
[](http://badge.fury.io/rb/query_report)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
[](https://codeclimate.com/github/ashrafuzzaman/query_report)
|
6
|
+
[](https://codeclimate.com/github/ashrafuzzaman/query_report)
|
7
|
+
|
8
|
+
###Write the action with a simple DSL and get a report with PDF and CSV export, gorgeous charts, out of box filters, with I18n support, etc...
|
9
|
+
|
10
|
+
Create a report in Rails
|
11
|
+
------------------------
|
12
|
+
|
13
|
+
You would have to do the following tasks to create a report in rails,
|
14
|
+
|
15
|
+
- Create a route
|
16
|
+
- Create an action with following logic
|
17
|
+
- Logic for filters
|
18
|
+
- Logic for pagination
|
19
|
+
- Create a view
|
20
|
+
- Write code to show HTML
|
21
|
+
- Write code to generate Graph
|
22
|
+
- Generate PDF with prawn pdf and graph
|
23
|
+
- Logic to send that PDF file as email
|
24
|
+
|
25
|
+
Create a report with query report
|
26
|
+
---------------------------------
|
27
|
+
|
28
|
+
- Create a route
|
29
|
+
- Create an action with following logic
|
30
|
+
- ~~Logic for filters~~
|
31
|
+
- ~~Logic for pagination~~
|
32
|
+
- ~~Create a view~~
|
33
|
+
- ~~Write code to show HTML~~
|
34
|
+
- ~~Write code to generate Graph~~
|
35
|
+
- ~~Generate PDF with prawn pdf and graph~~
|
36
|
+
- ~~Logic to send that PDF file as email~~
|
37
|
+
|
38
|
+
For email, you have to implement the popup once.
|
39
|
+
|
40
|
+
Features
|
41
|
+
--------
|
42
|
+
|
43
|
+
- Allow to use and reuse filters using [ransack](https://github.com/activerecord-hackery/ransack), and also with custom query
|
44
|
+
- Paginates [kaminari](https://github.com/amatsuda/kaminari)
|
45
|
+
- Supports ajax out of box
|
46
|
+
- Exports to PDF [prawn](https://github.com/prawnpdf/prawn), csv, json
|
47
|
+
- Supports to send report pdf as email
|
48
|
+
- Supports I18N
|
13
49
|
|
14
50
|
For a demo see [here](http://query-report-demo.herokuapp.com)
|
15
51
|
|
@@ -45,8 +81,8 @@ class InvoicesController < ApplicationController
|
|
45
81
|
column :title do |invoice|
|
46
82
|
link_to invoice.title, invoice
|
47
83
|
end
|
48
|
-
column :total_paid
|
49
|
-
column :total_charged
|
84
|
+
column :total_paid, show_total: true
|
85
|
+
column :total_charged, show_total: true
|
50
86
|
column :paid
|
51
87
|
end
|
52
88
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<table class="<%= QueryReport.config.record_table_class %>" cellpadding="0" cellspacing="0">
|
3
3
|
<thead>
|
4
4
|
<% report.columns.each do |column| %>
|
5
|
-
<th><%= column.sortable? ? sort_link(report.search, column.
|
5
|
+
<th><%= column.sortable? ? sort_link(report.search, column.sort_link_attribute, column.humanize, params, remote: @remote) : column.humanize %></th>
|
6
6
|
<% end %>
|
7
7
|
</thead>
|
8
8
|
|
data/lib/query_report/column.rb
CHANGED
@@ -8,14 +8,52 @@ module QueryReport
|
|
8
8
|
attr_accessor :columns
|
9
9
|
|
10
10
|
# Creates a filter and adds to the filters
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
11
|
+
# @param name the column on which the filter is done on
|
12
|
+
# @option options [Symbol] :type date | text | whatever
|
13
|
+
# @option options [String] :as The title of the column, by default it fetches from the I18n column translation, Model.human_attribute_name(column_name)
|
14
|
+
# @option options [Boolean] :show_total set true to calculate total for that column. It will render the total in the footer.
|
15
|
+
# @option options [Boolean] :only_on_web the column will appear on the web and not appear in PDF, CSV or JSON if set to true
|
16
|
+
# @option options [Boolean] :sortable if set to true then sorts on that column, but if the sorting has to be on a joint table then you have to specify the column on which the sorting will happen
|
17
|
+
# @option options :rowspan the rows with same values in the same column will span if set to true
|
18
|
+
#
|
19
|
+
# @example Row span
|
20
|
+
# column :invoiced_to_name, rowspan: true
|
21
|
+
# column :invoice_title
|
22
|
+
# column :invoice_date, rowspan: :invoiced_to_name
|
23
|
+
# ┌───────────┬────────────┬─────────────────┐
|
24
|
+
# │ Name │ Invoice │ Invoiced on │
|
25
|
+
# ├───────────┼────────────┼─────────────────┤
|
26
|
+
# │ │ Invoice1 │ │
|
27
|
+
# │ Jitu ├────────────┤ 2-2-2014 │
|
28
|
+
# │ │ Invoice2 │ │
|
29
|
+
# ├───────────┼────────────┼─────────────────┤
|
30
|
+
# │ Setu │ Invoice3 │ 2-2-2014 │
|
31
|
+
# └───────────┴────────────┴─────────────────┘
|
32
|
+
#
|
33
|
+
# @example Show total
|
34
|
+
# column :invoiced_to_name, rowspan: true
|
35
|
+
# column :invoice_title
|
36
|
+
# column :total_charged, show_total: true
|
37
|
+
# ┌───────────┬────────────┬─────────────────┐
|
38
|
+
# │ Name │ Invoice │ Total charge │
|
39
|
+
# ├───────────┼────────────┼─────────────────┤
|
40
|
+
# │ │ Invoice1 │ 100 │
|
41
|
+
# │ Jitu ├────────────┼─────────────────┤
|
42
|
+
# │ │ Invoice2 │ 120 │
|
43
|
+
# ├───────────┼────────────┼─────────────────┤
|
44
|
+
# │ Setu │ Invoice3 │ 80 │
|
45
|
+
# ├───────────┴────────────┼─────────────────┤
|
46
|
+
# │ Total │ 300 │
|
47
|
+
# └────────────────────────┴─────────────────┘
|
48
|
+
#
|
49
|
+
# @example Sorting
|
50
|
+
# column :invoice_date, sortable: true
|
51
|
+
# column :invoice_to, sortable: 'users.name'
|
52
|
+
#
|
53
|
+
# If you want to sort a column which is a column of the active record model that the query returns,
|
54
|
+
# then just set true to make the column sortable.
|
55
|
+
# If the column is from another table then you have to specify the column name.
|
56
|
+
#
|
19
57
|
def column(name, options={}, &block)
|
20
58
|
@columns << Column.new(self, name, options, block)
|
21
59
|
end
|
@@ -59,7 +97,11 @@ module QueryReport
|
|
59
97
|
end
|
60
98
|
|
61
99
|
def sortable?
|
62
|
-
@options[:sortable]
|
100
|
+
@options[:sortable].present? && @options[:sortable] != false
|
101
|
+
end
|
102
|
+
|
103
|
+
def sort_link_attribute
|
104
|
+
@options[:sortable] == true ? name : @options[:sortable]
|
63
105
|
end
|
64
106
|
|
65
107
|
def rowspan?
|
@@ -67,12 +109,16 @@ module QueryReport
|
|
67
109
|
end
|
68
110
|
|
69
111
|
def rowspan_column_humanized
|
112
|
+
return @rowspan_column_humanized if @rowspan_column_humanized
|
70
113
|
rowspan_column_name = @options[:rowspan].kind_of?(Symbol) ? @options[:rowspan] : self.name
|
71
114
|
|
72
115
|
report.columns.each do |column|
|
73
|
-
|
116
|
+
if column.name == rowspan_column_name
|
117
|
+
@rowspan_column_humanized = column.humanize
|
118
|
+
return @rowspan_column_humanized
|
119
|
+
end
|
74
120
|
end
|
75
|
-
|
121
|
+
@rowspan_column_humanized = self.humanize
|
76
122
|
end
|
77
123
|
|
78
124
|
def humanize
|
@@ -104,7 +150,6 @@ module QueryReport
|
|
104
150
|
end
|
105
151
|
end
|
106
152
|
end
|
107
|
-
|
108
153
|
end
|
109
154
|
end
|
110
155
|
end
|
data/lib/query_report/filter.rb
CHANGED
@@ -10,29 +10,38 @@ module QueryReport
|
|
10
10
|
module FilterModule
|
11
11
|
attr_accessor :filters, :search
|
12
12
|
|
13
|
-
# Creates a filter
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
13
|
+
# Creates a filter
|
14
|
+
# @param column the column on which the filter is done on, for manual filter the column name can be anything
|
15
|
+
# @option options [Symbol] :type date | text | whatever
|
16
|
+
# @option options [Array] :comp the comparators used for ransack search, [:gteq, :lteq]
|
17
|
+
# @option options [Boolean] :manual if set to true then that filter will not be applied, only will appear and can be used for custom application
|
18
|
+
# @option options :default support default filter value, can be one value or for range filter can be array
|
19
|
+
#
|
20
|
+
# @example Custom type
|
21
|
+
# filter :invoiced_to_id, type: :user
|
22
|
+
#
|
23
|
+
# # In a helper file define method
|
24
|
+
# def query_report_user_filter(name, user_id, options={})
|
25
|
+
# user = User.find(user_id)
|
26
|
+
# concat hidden_field_tag name, user_id, options
|
27
|
+
# text_field_tag "#{name}", user.name, class: 'user_search' #implement the filter, it can be autocomplete
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
|
21
31
|
def filter(column, options={}, &block)
|
22
32
|
@filters ||= []
|
23
33
|
@filters << Filter.new(@params, column, options, &block)
|
24
34
|
end
|
25
35
|
|
26
|
-
def has_filter?
|
27
|
-
filters.present?
|
28
|
-
end
|
29
|
-
|
30
36
|
def apply_filters(query, http_params)
|
31
37
|
# apply default filter
|
32
38
|
params = load_default_values_in_param(http_params) #need for ransack filter
|
33
39
|
@search = query.ransack(params[:q])
|
34
40
|
query = @search.result
|
35
41
|
|
42
|
+
#this is to fix a bug from ransack, as for ransack when the sorting is done from a joined table it does not sort by default
|
43
|
+
query = query.order(params[:q][:s]) if params[:q][:s]
|
44
|
+
|
36
45
|
#apply custom filter
|
37
46
|
@filters.select(&:custom?).each do |filter|
|
38
47
|
ordered_custom_param_values = ordered_param_value_objects(filter)
|
@@ -42,24 +51,6 @@ module QueryReport
|
|
42
51
|
query
|
43
52
|
end
|
44
53
|
|
45
|
-
def ordered_param_value_objects(filter)
|
46
|
-
filter.comparators.collect do |comp|
|
47
|
-
comp.objectified_param_value
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def load_default_values_in_param(http_params)
|
52
|
-
params = http_params.clone
|
53
|
-
params = params.merge(q: {}) unless params[:q]
|
54
|
-
params = params.merge(custom_search: {}) unless params[:custom_search]
|
55
|
-
@filters.each do |filter|
|
56
|
-
filter.comparators.each do |comparator|
|
57
|
-
params[filter.params_key][comparator.search_key] ||= comparator.param_value
|
58
|
-
end
|
59
|
-
end
|
60
|
-
params
|
61
|
-
end
|
62
|
-
|
63
54
|
class Filter
|
64
55
|
attr_reader :params, :column, :type, :comparators, :block, :options
|
65
56
|
|
@@ -120,5 +111,27 @@ module QueryReport
|
|
120
111
|
end
|
121
112
|
end
|
122
113
|
end
|
114
|
+
|
115
|
+
def has_filter?
|
116
|
+
filters.present?
|
117
|
+
end
|
118
|
+
|
119
|
+
def ordered_param_value_objects(filter)
|
120
|
+
filter.comparators.collect do |comp|
|
121
|
+
comp.objectified_param_value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def load_default_values_in_param(http_params)
|
126
|
+
params = http_params.clone
|
127
|
+
params = params.merge(q: {}) unless params[:q]
|
128
|
+
params = params.merge(custom_search: {}) unless params[:custom_search]
|
129
|
+
@filters.each do |filter|
|
130
|
+
filter.comparators.each do |comparator|
|
131
|
+
params[filter.params_key][comparator.search_key] ||= comparator.param_value
|
132
|
+
end
|
133
|
+
end
|
134
|
+
params
|
135
|
+
end
|
123
136
|
end
|
124
137
|
end
|
data/lib/query_report/helper.rb
CHANGED
@@ -11,12 +11,10 @@ module QueryReport
|
|
11
11
|
module Helper
|
12
12
|
|
13
13
|
# Generates the reports
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# options
|
17
|
-
#
|
18
|
-
# :skip_rendering - by default false, if set to true then the reporter will not render any thing, you will have to implement the rendering
|
19
|
-
# :per_page - If given then overrides the default kaminari per page option
|
14
|
+
# @param query The base query that the reporter with start with [filters will be applied on it]
|
15
|
+
# @option options [Integer] :per_page If given then overrides the default kaminari per page option
|
16
|
+
# @option options [Boolean] :custom_view by default false, if set to true then the reporter will look for the file to render
|
17
|
+
# @option options [Boolean] :skip_rendering by default false, if set to true then the reporter will not render any thing, you will have to implement the rendering
|
20
18
|
def reporter(query, options={}, &block)
|
21
19
|
@report ||= QueryReport::Report.new(params, view_context, options)
|
22
20
|
@report.query = query
|
@@ -78,7 +76,7 @@ module QueryReport
|
|
78
76
|
end
|
79
77
|
|
80
78
|
def send_pdf_email(email, subject, message, file_name, attachment)
|
81
|
-
@user = current_user
|
79
|
+
@user = current_user if defined? current_user
|
82
80
|
to = email.split(',')
|
83
81
|
ReportMailer.send_report(@user, to, subject, message, file_name, attachment).deliver
|
84
82
|
end
|
data/lib/query_report/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: query_report
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- A.K.M. Ashrafuzzaman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -252,3 +252,4 @@ signing_key:
|
|
252
252
|
specification_version: 4
|
253
253
|
summary: Structure you reports
|
254
254
|
test_files: []
|
255
|
+
has_rdoc:
|