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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTE1YjBhNmMwMmNiZTk4MjJiYTAzYmM4ZTc3Nzk3ZWM1NmRkOGUxNw==
4
+ Y2YyOTU4N2Y4MWQ1NDcxZTZmNmZiZTIxOTE4M2JkNGUwMTNjZDUyNA==
5
5
  data.tar.gz: !binary |-
6
- YzZkNGM1ZDMxOTZkZjg5YmMzMmExZDg1N2Q5YTEzYjNkOWJmOTNjYg==
6
+ ZDJkZThhYjEzYjBjYTc0YmM4NjU3NzkxZWM2NTgwMDFiZGM4ZWMzNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YWE1NDcwMTYwZDAzOWRiMTAwN2M2ZmIzYzBhOGVlZjYzZjI4ZDcyOTZjOGMy
10
- NDY1MjgyNGE4ZmU2ZDhkOTk4MTE3NTJhYWIxNzdjZTMyMzE2ZGJhYmIzZTBk
11
- ODk2OWUxNjFjNTMxMmViYTExMDI3MmE0ZTE2MzU2NWFiM2UzNzg=
9
+ NGFhZjQ2NTJjMzhkYTFmMzJkNGY4ZTA5NzQ0MWU5YzMwMGRiYzA4ODMwY2U0
10
+ YzAxZWM2ZDgwMDBiMTE3OTRkOGUxYTg5YzBhMTQ5MGE1MDg5NTM4YWUwMDk3
11
+ ODQwOTJlZWM1MmQ1NmJhYzViOWQ2OWFiZWFmMTI1NGFhMTNhYmI=
12
12
  data.tar.gz: !binary |-
13
- NDEyMWRjYjUxNmM5MzUwYzA1YWJmZDM1NDBkMzIzZDY4MzllOTlkZDJkZGM3
14
- NTc1MDU5MzI4YjdhMzM3ZjljYWRmZTMxZjVlMmQ1NGM1NDQ3NjM4MjBkYTQ0
15
- MWY5YzBlMTY1NjM0N2ZjNmY5NTU5YmY4NTg0YjlmNzhkNDYwMzg=
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 json response based on `ActiveRecord::Relation` objects.
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 grid:install`. This will generate grid initializer file with basic configuration.
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)
@@ -6,5 +6,5 @@ TheGrid.configure do |config|
6
6
  config.default_max_per_page = 25
7
7
 
8
8
  # Print json response with new lines and tabs
9
- config.prettify_json = ActionView::Base.pretty_print_json
10
- end
9
+ config.prettify_json = Rails.env.development?
10
+ end
@@ -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
@@ -10,21 +10,26 @@ module TheGrid
10
10
  end
11
11
 
12
12
  %{
13
- ::TheGrid::Builder.assemble(:view_type => ::TheGrid::Builder::Json, :scope => self) {
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, :view_type)
29
+ options.assert_valid_keys(:scope, :format)
25
30
 
26
31
  @_scope = options.delete(:scope)
27
- @_view_type = options.delete(:view_type)
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
- @_view_handler = @_view_type.new(relation, context)
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 { |name| instance_variable_set(name.to_sym, object.instance_variable_get(name)) }
55
+ vars.each{ |name| instance_variable_set(name.to_sym, object.instance_variable_get(name)) }
58
56
  end
59
57
 
60
58
  end
@@ -1,3 +1,3 @@
1
1
  module TheGrid
2
- VERSION = "1.0.10"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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
@@ -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 { TheGrid::Builder::Json.new(relation, context) }
5
+ subject{ TheGrid::Builder::Json.new(Object.new, build_context) }
5
6
 
6
- before(:each) { subject.api.stub(:compose!) { subject.api.options[:max_page] = 25 } }
7
+ include_examples "for Grid View Builder"
8
+ before(:each) { subject.api.stub(:compose!){ subject.api.options[:max_page] = 25 } }
7
9
 
8
- let(:relation) { double('Relation').as_null_object }
9
- let(:context) { create_context.tap { |c| c.stub(:assemble => [1,2,3,4]) } }
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, "123" }
33
- assembled_result.should eql({"status" => "error", "message" => "123"})
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 "hello_world"
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.10
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-17 00:00:00.000000000 Z
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