the_grid 1.0.10 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +36 -2
- data/lib/generators/the_grid/install/templates/the_grid.rb +2 -2
- data/lib/the_grid/builder/csv.rb +45 -0
- data/lib/the_grid/builder.rb +11 -13
- data/lib/the_grid/version.rb +1 -1
- data/spec/builder/csv_spec.rb +47 -0
- data/spec/builder/json_spec.rb +14 -16
- data/spec/builder/view_builder_helper.rb +10 -0
- data/the_grid.gemspec +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2YyOTU4N2Y4MWQ1NDcxZTZmNmZiZTIxOTE4M2JkNGUwMTNjZDUyNA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZDJkZThhYjEzYjBjYTc0YmM4NjU3NzkxZWM2NTgwMDFiZGM4ZWMzNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NGFhZjQ2NTJjMzhkYTFmMzJkNGY4ZTA5NzQ0MWU5YzMwMGRiYzA4ODMwY2U0
|
10
|
+
YzAxZWM2ZDgwMDBiMTE3OTRkOGUxYTg5YzBhMTQ5MGE1MDg5NTM4YWUwMDk3
|
11
|
+
ODQwOTJlZWM1MmQ1NmJhYzViOWQ2OWFiZWFmMTI1NGFhMTNhYmI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YjViYzJjMWZhZmMzMTY4YmE2YzVlOTQ3YzU3YTBiOWZiY2I3NDU0MDU4MTY0
|
14
|
+
ZDJlYjY4MzkyYmUwNzhhYmE2MjllMWZlODJhYWY1NTExNjFjMzE4YmE4MjNi
|
15
|
+
MDAyN2FjNTA1YTQ4NmUzZThjY2FmNjkwZTU2YzZmMWQzOWUwNTQ=
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
Yet Another Grid
|
2
2
|
=========
|
3
3
|
|
4
|
-
This plugin is designed to provide API for building
|
4
|
+
This plugin is designed to provide API for building response based on `ActiveRecord::Relation` objects (json, csv, even using custom view builder).
|
5
5
|
It makes much easier to fetch information from database for displaying it using JavaScript MV* based frameworks such as Knockout, Backbone, Angular, etc.
|
6
6
|
|
7
7
|
## Getting started
|
8
8
|
|
9
9
|
First of all specify grid in your Gemfile and run `bundle install`.
|
10
|
-
After gem is installed you need to run `rails generate
|
10
|
+
After gem is installed you need to run `rails generate the_grid:install`. This will generate grid initializer file with basic configuration.
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
@@ -37,6 +37,8 @@ grid_for @articles, :per_page => 25 do
|
|
37
37
|
end
|
38
38
|
```
|
39
39
|
|
40
|
+
The same grid defenition can be used with different formats.
|
41
|
+
|
40
42
|
## API
|
41
43
|
|
42
44
|
The API is based on commands. Term *command* describes client's action which can be simple or complicated as well.
|
@@ -422,6 +424,38 @@ grid_for @groups, :per_page => 2 do
|
|
422
424
|
end
|
423
425
|
end
|
424
426
|
```
|
427
|
+
#### CSV builder
|
428
|
+
|
429
|
+
It's possible to generate csv using grid views.
|
430
|
+
The main power is that this view builder also responds to also the api request parameters except pagination.
|
431
|
+
So, it's possible to filter records for output csv. All what you need is just create a simple view:
|
432
|
+
```ruby
|
433
|
+
# app/views/products/index.csv.grid_builder
|
434
|
+
grid_for @products do
|
435
|
+
column :title
|
436
|
+
column :qty
|
437
|
+
column :created_at
|
438
|
+
end
|
439
|
+
```
|
440
|
+
And in your controller
|
441
|
+
```ruby
|
442
|
+
# app/controllers/products_controller.rb
|
443
|
+
class ProductsController < ApplicationController
|
444
|
+
respond_to :csv, :html
|
445
|
+
|
446
|
+
def index
|
447
|
+
@products = Product.active
|
448
|
+
respond_with @products
|
449
|
+
end
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
453
|
+
Then you can send requests like:
|
454
|
+
```
|
455
|
+
http://your.domain.com/route.csv?cmd[]=filter&filters[is_active]=1
|
456
|
+
```
|
457
|
+
and will get csv file which contains only filtered active products.
|
458
|
+
|
425
459
|
## License
|
426
460
|
|
427
461
|
Released under the [MIT License](http://www.opensource.org/licenses/MIT)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module TheGrid
|
4
|
+
class Builder::Csv
|
5
|
+
attr_reader :api, :context
|
6
|
+
|
7
|
+
BATCH_SIZE = 1000
|
8
|
+
|
9
|
+
def initialize(relation, context)
|
10
|
+
@api = TheGrid::Api.new(relation)
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
def assemble_with(params)
|
15
|
+
options = params.merge context.params
|
16
|
+
api.compose!(options.merge :per_page => BATCH_SIZE)
|
17
|
+
generate_csv_with(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def generate_csv_with(options)
|
23
|
+
CSV.generate do |csv|
|
24
|
+
csv << headers
|
25
|
+
put_relation_to(csv)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def put_relation_to(csv)
|
30
|
+
(1..api.options[:max_page]).each do |page|
|
31
|
+
relation = api.run_command!(:paginate, :page => page, :per_page => BATCH_SIZE)
|
32
|
+
put_records_to(csv, relation)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def put_records_to(csv, records)
|
37
|
+
context.assemble(records).each{ |row| csv << row.values }
|
38
|
+
end
|
39
|
+
|
40
|
+
def headers
|
41
|
+
context.options[:headers] || context.columns.keys.map { |col| col.to_s.titleize }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/the_grid/builder.rb
CHANGED
@@ -10,21 +10,26 @@ module TheGrid
|
|
10
10
|
end
|
11
11
|
|
12
12
|
%{
|
13
|
-
::TheGrid::Builder.assemble(:
|
13
|
+
::TheGrid::Builder.assemble(:format => #{template.formats.first.inspect}, :scope => self) {
|
14
14
|
#{source}
|
15
15
|
}
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
+
def self.detect_view(format)
|
20
|
+
@@view_types ||= {}
|
21
|
+
@@view_types[format] ||= "the_grid/builder/#{format}".camelize.constantize
|
22
|
+
end
|
23
|
+
|
19
24
|
def self.assemble(options, &block)
|
20
|
-
new(options, &block)
|
25
|
+
new(options, &block).instance_eval(&block)
|
21
26
|
end
|
22
27
|
|
23
28
|
def initialize(options, &block)
|
24
|
-
options.assert_valid_keys(:scope, :
|
29
|
+
options.assert_valid_keys(:scope, :format)
|
25
30
|
|
26
31
|
@_scope = options.delete(:scope)
|
27
|
-
@_view_type = options.delete(:
|
32
|
+
@_view_type = self.class.detect_view(options.delete(:format))
|
28
33
|
|
29
34
|
copy_instance_variables_from(@_scope) if @_scope
|
30
35
|
self.instance_eval(&block)
|
@@ -32,11 +37,7 @@ module TheGrid
|
|
32
37
|
|
33
38
|
def grid_for(relation, options = {}, &block)
|
34
39
|
context = Context.new(options.merge(:scope => @_scope), &block)
|
35
|
-
@
|
36
|
-
end
|
37
|
-
|
38
|
-
def assemble(&block)
|
39
|
-
@_view_handler.assemble_with(@_scope.params, &block)
|
40
|
+
@_view_type.new(relation, context)
|
40
41
|
end
|
41
42
|
|
42
43
|
def method_missing(name, *args, &block)
|
@@ -47,14 +48,11 @@ module TheGrid
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
def to_s; assemble;end
|
51
|
-
def to_str; assemble;end
|
52
|
-
|
53
51
|
private
|
54
52
|
|
55
53
|
def copy_instance_variables_from(object)
|
56
54
|
vars = object.instance_variables.map(&:to_s)
|
57
|
-
vars.each
|
55
|
+
vars.each{ |name| instance_variable_set(name.to_sym, object.instance_variable_get(name)) }
|
58
56
|
end
|
59
57
|
|
60
58
|
end
|
data/lib/the_grid/version.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'view_builder_helper'
|
3
|
+
|
4
|
+
describe TheGrid::Builder::Csv do
|
5
|
+
subject{ TheGrid::Builder::Csv.new(relation, build_context) }
|
6
|
+
|
7
|
+
include_examples "for Grid View Builder"
|
8
|
+
before(:each) { subject.api.stub(:compose!){ subject.api.options[:max_page] = 1 } }
|
9
|
+
|
10
|
+
let(:relation) { double.as_null_object }
|
11
|
+
let(:record) {{ :id => 1, :name => "Name", :status => "Active", :text => "Text" }}
|
12
|
+
let(:records) {[ record, record, record ]}
|
13
|
+
let(:params) {{ :cmd => [:sort], :field => :name, :order => :desc, :per_page => subject.class.const_get("BATCH_SIZE") }}
|
14
|
+
|
15
|
+
it "generates expected csv string" do
|
16
|
+
subject.assemble_with(params).should eql generate_csv(records, subject.context.options[:headers])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "uses titleized column names if headers are not specified" do
|
20
|
+
subject.context.stub(:options => {})
|
21
|
+
headers = record.keys.map{|c| c.to_s.titleize }
|
22
|
+
subject.assemble_with(params).should eql generate_csv(records, headers)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "generates csv records in batches" do
|
26
|
+
subject.api.should_receive(:run_command!).with(:paginate, :page => 1, :per_page => params[:per_page])
|
27
|
+
subject.assemble_with(params);
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def generate_csv(records, headers)
|
32
|
+
CSV.generate do |csv|
|
33
|
+
csv << headers
|
34
|
+
records.each{ |item| csv << item.values }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_context
|
39
|
+
TheGrid::Builder::Context.new do
|
40
|
+
headers "Id", "Title", "Status", "Description"
|
41
|
+
column :name
|
42
|
+
column :status
|
43
|
+
column :text
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/spec/builder/json_spec.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require_relative 'view_builder_helper'
|
2
3
|
|
3
4
|
describe TheGrid::Builder::Json do
|
4
|
-
subject
|
5
|
+
subject{ TheGrid::Builder::Json.new(Object.new, build_context) }
|
5
6
|
|
6
|
-
|
7
|
+
include_examples "for Grid View Builder"
|
8
|
+
before(:each) { subject.api.stub(:compose!){ subject.api.options[:max_page] = 25 } }
|
7
9
|
|
8
|
-
let(:
|
9
|
-
let(:
|
10
|
-
let(:params) {{ :cmd => [:sort], :field => :name, :order => :desc }}
|
10
|
+
let(:records) {[ 1, 2, 3, 4 ]}
|
11
|
+
let(:params) {{ :cmd => [:sort], :field => :name, :order => :desc }}
|
11
12
|
|
12
|
-
let(:meta) {{ "meta" => {"api_key" => context.options[:api_key]}, "columns" => columns }}
|
13
|
-
let(:columns) { context.visible_columns.stringify_keys.map{ |n, o| o.merge "name" => n } }
|
14
|
-
let(:json_schema) {{ "max_page" => 25, "items" => context.assemble }}
|
13
|
+
let(:meta) {{ "meta" => {"api_key" => subject.context.options[:api_key]}, "columns" => columns }}
|
14
|
+
let(:columns) { subject.context.visible_columns.stringify_keys.map{ |n, o| o.merge "name" => n } }
|
15
|
+
let(:json_schema) {{ "max_page" => 25, "items" => subject.context.assemble }}
|
15
16
|
let(:assembled_result) { JSON.parse(subject.assemble_with(params)) }
|
16
17
|
|
17
18
|
it "merges params with context options" do
|
18
|
-
subject.api.should_receive(:compose!).with(params.merge context.options)
|
19
|
+
subject.api.should_receive(:compose!).with(params.merge subject.context.options)
|
19
20
|
subject.assemble_with params
|
20
21
|
end
|
21
22
|
|
@@ -29,16 +30,13 @@ describe TheGrid::Builder::Json do
|
|
29
30
|
end
|
30
31
|
|
31
32
|
it "generates json notification when get wrong argument" do
|
32
|
-
subject.api.stub(:compose!) { raise ArgumentError, "
|
33
|
-
assembled_result.should eql
|
33
|
+
subject.api.stub(:compose!) { raise ArgumentError, "my message" }
|
34
|
+
assembled_result.should eql "status" => "error", "message" => "my message"
|
34
35
|
end
|
35
36
|
|
36
|
-
|
37
|
-
def create_context
|
37
|
+
def build_context
|
38
38
|
TheGrid::Builder::Context.new do
|
39
|
-
api_key
|
40
|
-
delegate :sort => :articles, :filter => :articles
|
41
|
-
|
39
|
+
api_key 1234567
|
42
40
|
column :name
|
43
41
|
column :is_active
|
44
42
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
shared_examples "for Grid View Builder" do
|
2
|
+
before(:each) { subject.context.stub(:assemble => records) }
|
3
|
+
|
4
|
+
it { should respond_to(:assemble_with) }
|
5
|
+
|
6
|
+
it "merges context with params" do
|
7
|
+
subject.api.should_receive(:compose!).with(params.merge subject.context.options)
|
8
|
+
subject.assemble_with(params)
|
9
|
+
end
|
10
|
+
end
|
data/the_grid.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.description = <<-EOF
|
16
16
|
Provides json API for building ActiveRecord::Relation's. It makes much easier to fetch information from database for displaying it using JavaScript MV* based frameworks such as Knockout, Backbone, Angular, etc.
|
17
17
|
|
18
|
-
Tags: json, grid, api, grid builder, activerecord relation builder, relation
|
18
|
+
Tags: json, csv, grid, api, grid builder, activerecord relation builder, relation
|
19
19
|
EOF
|
20
20
|
|
21
21
|
s.post_install_message = <<-_MSG_
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: the_grid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergiy Stotskiy
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -72,7 +72,7 @@ description: ! 'Provides json API for building ActiveRecord::Relation''s. It ma
|
|
72
72
|
MV* based frameworks such as Knockout, Backbone, Angular, etc.
|
73
73
|
|
74
74
|
|
75
|
-
Tags: json, grid, api, grid builder, activerecord relation builder, relation
|
75
|
+
Tags: json, csv, grid, api, grid builder, activerecord relation builder, relation
|
76
76
|
|
77
77
|
'
|
78
78
|
email: sergiy.stotskiy@gmail.com
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/the_grid/api/command/sort.rb
|
98
98
|
- lib/the_grid/builder.rb
|
99
99
|
- lib/the_grid/builder/context.rb
|
100
|
+
- lib/the_grid/builder/csv.rb
|
100
101
|
- lib/the_grid/builder/json.rb
|
101
102
|
- lib/the_grid/config.rb
|
102
103
|
- lib/the_grid/version.rb
|
@@ -109,7 +110,9 @@ files:
|
|
109
110
|
- spec/api/command_spec.rb
|
110
111
|
- spec/api_spec.rb
|
111
112
|
- spec/builder/context_spec.rb
|
113
|
+
- spec/builder/csv_spec.rb
|
112
114
|
- spec/builder/json_spec.rb
|
115
|
+
- spec/builder/view_builder_helper.rb
|
113
116
|
- spec/config_spec.rb
|
114
117
|
- spec/spec_helper.rb
|
115
118
|
- the_grid.gemspec
|