batch_actions 0.0.1
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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +6 -0
- data/batch_actions.gemspec +23 -0
- data/lib/batch_actions.rb +36 -0
- data/lib/batch_actions/class_methods.rb +60 -0
- data/lib/batch_actions/version.rb +3 -0
- data/spec/batch_actions_spec.rb +155 -0
- data/spec/spec_helper.rb +41 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e68fc1158fbe9d59d7e11c037f3cc580d855e314
|
4
|
+
data.tar.gz: 203625073e57c12ae947b3016283e0eb044339af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b397f3158bfc0e7e9f0d5a4072922804c2c197f51eeaa52604b4589a73324497dafc6c5a5f0d4d0aeb476ecd6e3aef6cb8d100f91bbbde4e0274108cd8f207f6
|
7
|
+
data.tar.gz: e1db247358fb5e19eccb1322217de7f0a73ee49b79645555fc3f978ec577e5a606a8bea5a3ff1c1b3a0eb089fbb306ddd7d9ed48f7d60eb66444d8abe5659e7d
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--tty --colour
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sergey Gridasov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# BatchActions
|
2
|
+
|
3
|
+
This gem adds generic support for batch actions to Rails controllers.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/grindars/batch_actions)
|
6
|
+
[](https://codeclimate.com/github/grindars/batch_actions)
|
7
|
+
|
8
|
+
Sponsored by [Evil Martians](http://evilmartians.com/).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'batch_actions'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install batch_actions
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class PostController < ApplicationController
|
28
|
+
include BatchActions
|
29
|
+
|
30
|
+
batch_model Post
|
31
|
+
|
32
|
+
# Runs `model.publish` for every model from params[:ids]
|
33
|
+
batch_action :publish
|
34
|
+
|
35
|
+
# Runs `model.destroy` for every model from params[:ids] or throws exception unless you can
|
36
|
+
batch_action :destroy, if: ->() { can? :destroy, Post }
|
37
|
+
|
38
|
+
# Runs block for every model from params[:ids]
|
39
|
+
batch_action :specific do |objects|
|
40
|
+
objects.each{|x| x.specific!}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Runs `model.resurrect` for every model from returned relation
|
44
|
+
batch_action :resurrect, :scope => ->(ids) { Post.where(other_ids: ids) }
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Note that you can omit `batch_model` call if you use the [inherited_resources](https://github.com/josevalim/inherited_resources) gem. It grabs your model class from `resource_class`.
|
49
|
+
|
50
|
+
There's one more important thing to know: set of active batch actions can be retrieved from controller by calling `batch_actions` on controller instance.
|
51
|
+
|
52
|
+
## Contributing
|
53
|
+
|
54
|
+
1. Fork it
|
55
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
56
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
57
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
58
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'batch_actions/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "batch_actions"
|
8
|
+
spec.version = BatchActions::VERSION
|
9
|
+
spec.authors = ["Sergey Gridasov"]
|
10
|
+
spec.email = ["grindars@gmail.com"]
|
11
|
+
spec.description = %q{Batch action support for Rails.}
|
12
|
+
spec.summary = %q{Batch action support for Rails.}
|
13
|
+
spec.homepage = "https://github.com/grindars/batch_actions"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "batch_actions/version"
|
2
|
+
require "batch_actions/class_methods"
|
3
|
+
|
4
|
+
module BatchActions
|
5
|
+
def batch_actions
|
6
|
+
return [] unless self.class.instance_variable_defined? :@batch_actions
|
7
|
+
|
8
|
+
actions = self.class.instance_variable_get :@batch_actions
|
9
|
+
allowed = []
|
10
|
+
|
11
|
+
actions.each do |keyword, condition|
|
12
|
+
if instance_exec(&condition)
|
13
|
+
allowed << keyword
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
allowed
|
18
|
+
end
|
19
|
+
|
20
|
+
def batch_action
|
21
|
+
action = params[:name]
|
22
|
+
|
23
|
+
raise "action is not allowed" unless batch_actions.include? action.to_sym
|
24
|
+
|
25
|
+
send(:"batch_#{action}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.extend ClassMethods
|
30
|
+
|
31
|
+
if defined?(InheritedResources::Base) &&
|
32
|
+
base < InheritedResources::Base
|
33
|
+
base.batch_model base.resource_class
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module BatchActions
|
2
|
+
module ClassMethods
|
3
|
+
def batch_model(klass)
|
4
|
+
@batch_model = klass
|
5
|
+
end
|
6
|
+
|
7
|
+
def batch_action(keyword, opts = {}, &block)
|
8
|
+
@batch_actions = {} if @batch_actions.nil?
|
9
|
+
|
10
|
+
if opts.include? :model
|
11
|
+
model = opts[:model]
|
12
|
+
elsif !@batch_model.nil?
|
13
|
+
model = @batch_model
|
14
|
+
else
|
15
|
+
raise ArgumentError, "model must be specified"
|
16
|
+
end
|
17
|
+
|
18
|
+
if block_given?
|
19
|
+
apply = block
|
20
|
+
else
|
21
|
+
apply = ->(objects) do
|
22
|
+
objects.each do |object|
|
23
|
+
object.send(keyword)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if opts.include? :scope
|
29
|
+
scope = opts[:scope]
|
30
|
+
else
|
31
|
+
scope = ->(model) do
|
32
|
+
model.where(:id => params[:ids])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if opts.include? :if
|
37
|
+
condition = opts[:if]
|
38
|
+
else
|
39
|
+
condition = ->() do
|
40
|
+
if self.respond_to? :can?
|
41
|
+
can? keyword, model
|
42
|
+
else
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@batch_actions[keyword] = condition
|
49
|
+
|
50
|
+
define_method(:"batch_#{keyword}") do
|
51
|
+
result = instance_exec(&condition)
|
52
|
+
|
53
|
+
raise "action is not allowed" unless result
|
54
|
+
|
55
|
+
objects = instance_exec(model, &scope)
|
56
|
+
apply.call(objects)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchActions do
|
4
|
+
it "generates batch actions" do
|
5
|
+
ctrl = mock_controller(
|
6
|
+
:ids => [ 1, 2 ]
|
7
|
+
) do
|
8
|
+
batch_model TestModel
|
9
|
+
batch_action :test1
|
10
|
+
end
|
11
|
+
|
12
|
+
times = 0
|
13
|
+
|
14
|
+
TestModel.should_receive(:where).with({ :id => [ 1, 2 ]}).and_call_original
|
15
|
+
TestModel.any_instance.stub(:test1) { times += 1 }
|
16
|
+
|
17
|
+
ctrl.batch_test1
|
18
|
+
|
19
|
+
times.should == 2
|
20
|
+
end
|
21
|
+
|
22
|
+
it "requires a model to be specified" do
|
23
|
+
expect do
|
24
|
+
mock_controller do
|
25
|
+
batch_action :test1
|
26
|
+
end
|
27
|
+
end.to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "allows per-action override of a model" do
|
31
|
+
ctrl = mock_controller(
|
32
|
+
:ids => [ 1 ]
|
33
|
+
) do
|
34
|
+
batch_model TestModel
|
35
|
+
|
36
|
+
batch_action :test1
|
37
|
+
batch_action :test2, :model => TestModel2
|
38
|
+
end
|
39
|
+
|
40
|
+
TestModel.should_receive(:where).with({ :id => [ 1 ]}).and_call_original
|
41
|
+
TestModel2.should_receive(:where).with({ :id => [ 1 ]}).and_call_original
|
42
|
+
|
43
|
+
TestModel.any_instance.should_receive(:test1).and_return(nil)
|
44
|
+
TestModel2.any_instance.should_receive(:test2).and_return(nil)
|
45
|
+
|
46
|
+
ctrl.batch_test1
|
47
|
+
ctrl.batch_test2
|
48
|
+
end
|
49
|
+
|
50
|
+
it "allows to specify scope" do
|
51
|
+
scope_called = false
|
52
|
+
|
53
|
+
instance = TestModel.new
|
54
|
+
instance.should_receive(:test1).and_return(nil)
|
55
|
+
|
56
|
+
ctrl = mock_controller(
|
57
|
+
:ids => [ 1 ]
|
58
|
+
) do
|
59
|
+
batch_model TestModel
|
60
|
+
|
61
|
+
batch_action :test1, :scope => ->(model) do
|
62
|
+
scope_called = true
|
63
|
+
|
64
|
+
[ instance ]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
ctrl.batch_test1
|
69
|
+
|
70
|
+
scope_called.should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "allows to override default apply" do
|
74
|
+
block_called = nil
|
75
|
+
|
76
|
+
ctrl = mock_controller(
|
77
|
+
:ids => [ 1 ]
|
78
|
+
) do
|
79
|
+
batch_model TestModel
|
80
|
+
|
81
|
+
batch_action(:test1) do |objects|
|
82
|
+
block_called = objects
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
ctrl.batch_test1
|
87
|
+
|
88
|
+
block_called.should_not be_nil
|
89
|
+
block_called.length.should == 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it "supports :if" do
|
93
|
+
ctrl = mock_controller(
|
94
|
+
:ids => [ 1 ]
|
95
|
+
) do
|
96
|
+
batch_model TestModel
|
97
|
+
|
98
|
+
batch_action :test, :if => ->() { false }
|
99
|
+
end
|
100
|
+
|
101
|
+
expect { ctrl.batch_test1 }.to raise_error
|
102
|
+
ctrl.batch_actions.should be_empty
|
103
|
+
end
|
104
|
+
|
105
|
+
it "implements batch_actions" do
|
106
|
+
ctrl = mock_controller do
|
107
|
+
batch_model TestModel
|
108
|
+
|
109
|
+
batch_action :test1
|
110
|
+
batch_action :test2
|
111
|
+
batch_action :test3, :if => ->() { false }
|
112
|
+
end
|
113
|
+
|
114
|
+
ctrl.batch_actions.should == [ :test1, :test2 ]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "supports InheritedResources" do
|
118
|
+
expect do
|
119
|
+
mock_controller(:parent => InheritedResources::Base) do
|
120
|
+
batch_action :test1
|
121
|
+
end
|
122
|
+
end.to_not raise_error
|
123
|
+
end
|
124
|
+
|
125
|
+
it "supports CanCan" do
|
126
|
+
ctrl = mock_controller do
|
127
|
+
batch_model TestModel
|
128
|
+
|
129
|
+
batch_action :test1
|
130
|
+
batch_action :test2
|
131
|
+
|
132
|
+
def can?(keyword, model)
|
133
|
+
keyword == :test1
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
ctrl.batch_actions.should == [ :test1 ]
|
138
|
+
end
|
139
|
+
|
140
|
+
it "implements batch_action" do
|
141
|
+
[ "test1", "test2" ].each do |action|
|
142
|
+
ctrl = mock_controller(
|
143
|
+
:ids => [ 1 ],
|
144
|
+
:name => action
|
145
|
+
) do
|
146
|
+
batch_model TestModel
|
147
|
+
batch_action :test1
|
148
|
+
batch_action :test2
|
149
|
+
end
|
150
|
+
|
151
|
+
TestModel.any_instance.should_receive(action.to_sym).and_return(nil)
|
152
|
+
ctrl.batch_action
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
require 'batch_actions'
|
5
|
+
|
6
|
+
class TestModel
|
7
|
+
def self.where(query)
|
8
|
+
query[:id].map { self.new }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestModel2
|
13
|
+
def self.where(query)
|
14
|
+
query[:id].map { self.new }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module InheritedResources
|
19
|
+
class Base
|
20
|
+
def self.resource_class
|
21
|
+
TestModel
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def mock_controller(params = {}, &block)
|
27
|
+
parent = params.delete(:parent) || Object
|
28
|
+
|
29
|
+
mock_class = Class.new(parent) do
|
30
|
+
include BatchActions
|
31
|
+
|
32
|
+
def params
|
33
|
+
self.class.instance_variable_get :@params
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
mock_class.class_exec(&block)
|
38
|
+
mock_class.instance_variable_set :@params, params
|
39
|
+
|
40
|
+
mock_class.new
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: batch_actions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sergey Gridasov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Batch action support for Rails.
|
42
|
+
email:
|
43
|
+
- grindars@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .rspec
|
50
|
+
- .travis.yml
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- batch_actions.gemspec
|
56
|
+
- lib/batch_actions.rb
|
57
|
+
- lib/batch_actions/class_methods.rb
|
58
|
+
- lib/batch_actions/version.rb
|
59
|
+
- spec/batch_actions_spec.rb
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
homepage: https://github.com/grindars/batch_actions
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.0.0
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: Batch action support for Rails.
|
85
|
+
test_files:
|
86
|
+
- spec/batch_actions_spec.rb
|
87
|
+
- spec/spec_helper.rb
|