query_report 1.0.23 → 1.0.24
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://api.travis-ci.org/ashrafuzzaman/query_report.png?branch=master)](http://travis-ci.org/ashrafuzzaman/query_report)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/query_report.png)](http://badge.fury.io/rb/query_report)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
[![Code Climate](https://codeclimate.com/github/ashrafuzzaman/query_report.png)](https://codeclimate.com/github/ashrafuzzaman/query_report)
|
6
|
+
[![Code coverage](https://codeclimate.com/github/ashrafuzzaman/query_report/coverage.png)](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:
|