filterable-by 0.4.0 → 0.5.2
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 +5 -5
- data/.github/workflows/ruby.yml +21 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +10 -6
- data/Gemfile.lock +74 -52
- data/LICENSE +20 -0
- data/README.md +16 -30
- data/Rakefile +1 -1
- data/filterable-by.gemspec +5 -6
- data/lib/filterable_by.rb +31 -15
- data/spec/active_record/filterable_by_spec.rb +80 -0
- data/spec/spec_helper.rb +32 -12
- metadata +11 -12
- data/.rubocop_todo.yml +0 -40
- data/.travis.yml +0 -6
- data/spec/filterable_by_spec.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8a45bdeb246550581221e6a721af41f27e355b9d87d1fd8dd791731142bba9cd
|
4
|
+
data.tar.gz: 06f4640997ef9fbfc88b6cedb943cf0840c0e643c7012ffd441700e52495113e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c292090ad77af10f1729f4ad652fb84595fe20d866bf4ab221d642465fc56fa4073dc7cc2ed2469b9a92169e418f2860f44ea4702bbf4cbf34e1591b07645077
|
7
|
+
data.tar.gz: '08a1ec2870b5da50e5b41b35a06e8adf5b72f375c50fb2bc3009d9a4c17f5140b4f44f44ffc764aa8f73703a9f041610b37075ebbedabfd84db362690562b9a2'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [main]
|
6
|
+
pull_request:
|
7
|
+
branches: [main]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ["2.6", "2.7", "3.0"]
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.ruby-version }}
|
20
|
+
bundler-cache: true
|
21
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-bsm:
|
3
|
+
- default.yml
|
4
|
+
inherit_mode:
|
5
|
+
merge:
|
6
|
+
- Exclude
|
2
7
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
Max: 120
|
8
|
+
AllCops:
|
9
|
+
TargetRubyVersion: "2.6"
|
10
|
+
Naming/FileName:
|
11
|
+
Exclude: [lib/filterable-by.rb]
|
data/Gemfile.lock
CHANGED
@@ -1,64 +1,86 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
filterable-by (0.
|
4
|
+
filterable-by (0.5.2)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activemodel (
|
12
|
-
activesupport (=
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rspec-
|
40
|
-
|
41
|
-
rspec-
|
42
|
-
rspec-
|
43
|
-
rspec-support (~> 3.3.0)
|
44
|
-
rspec-expectations (3.3.1)
|
11
|
+
activemodel (6.1.3)
|
12
|
+
activesupport (= 6.1.3)
|
13
|
+
activerecord (6.1.3)
|
14
|
+
activemodel (= 6.1.3)
|
15
|
+
activesupport (= 6.1.3)
|
16
|
+
activesupport (6.1.3)
|
17
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
18
|
+
i18n (>= 1.6, < 2)
|
19
|
+
minitest (>= 5.1)
|
20
|
+
tzinfo (~> 2.0)
|
21
|
+
zeitwerk (~> 2.3)
|
22
|
+
ast (2.4.2)
|
23
|
+
concurrent-ruby (1.1.8)
|
24
|
+
diff-lcs (1.4.4)
|
25
|
+
i18n (1.8.9)
|
26
|
+
concurrent-ruby (~> 1.0)
|
27
|
+
minitest (5.14.4)
|
28
|
+
parallel (1.20.1)
|
29
|
+
parser (3.0.0.0)
|
30
|
+
ast (~> 2.4.1)
|
31
|
+
rack (2.2.3)
|
32
|
+
rainbow (3.0.0)
|
33
|
+
rake (13.0.3)
|
34
|
+
regexp_parser (2.1.1)
|
35
|
+
rexml (3.2.4)
|
36
|
+
rspec (3.10.0)
|
37
|
+
rspec-core (~> 3.10.0)
|
38
|
+
rspec-expectations (~> 3.10.0)
|
39
|
+
rspec-mocks (~> 3.10.0)
|
40
|
+
rspec-core (3.10.1)
|
41
|
+
rspec-support (~> 3.10.0)
|
42
|
+
rspec-expectations (3.10.1)
|
45
43
|
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
-
rspec-support (~> 3.
|
47
|
-
rspec-mocks (3.
|
44
|
+
rspec-support (~> 3.10.0)
|
45
|
+
rspec-mocks (3.10.2)
|
48
46
|
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
-
rspec-support (~> 3.
|
50
|
-
rspec-support (3.
|
51
|
-
rubocop (
|
52
|
-
|
53
|
-
parser (>=
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
47
|
+
rspec-support (~> 3.10.0)
|
48
|
+
rspec-support (3.10.2)
|
49
|
+
rubocop (1.11.0)
|
50
|
+
parallel (~> 1.10)
|
51
|
+
parser (>= 3.0.0.0)
|
52
|
+
rainbow (>= 2.2.2, < 4.0)
|
53
|
+
regexp_parser (>= 1.8, < 3.0)
|
54
|
+
rexml
|
55
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
56
|
+
ruby-progressbar (~> 1.7)
|
57
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
58
|
+
rubocop-ast (1.4.1)
|
59
|
+
parser (>= 2.7.1.5)
|
60
|
+
rubocop-bsm (0.5.4)
|
61
|
+
rubocop (~> 1.0)
|
62
|
+
rubocop-performance
|
63
|
+
rubocop-rails
|
64
|
+
rubocop-rake
|
65
|
+
rubocop-rspec
|
66
|
+
rubocop-performance (1.10.1)
|
67
|
+
rubocop (>= 0.90.0, < 2.0)
|
68
|
+
rubocop-ast (>= 0.4.0)
|
69
|
+
rubocop-rails (2.9.1)
|
70
|
+
activesupport (>= 4.2.0)
|
71
|
+
rack (>= 1.1)
|
72
|
+
rubocop (>= 0.90.0, < 2.0)
|
73
|
+
rubocop-rake (0.5.1)
|
74
|
+
rubocop
|
75
|
+
rubocop-rspec (2.2.0)
|
76
|
+
rubocop (~> 1.0)
|
77
|
+
rubocop-ast (>= 1.1.0)
|
78
|
+
ruby-progressbar (1.11.0)
|
79
|
+
sqlite3 (1.4.2)
|
80
|
+
tzinfo (2.0.4)
|
81
|
+
concurrent-ruby (~> 1.0)
|
82
|
+
unicode-display_width (2.0.0)
|
83
|
+
zeitwerk (2.4.2)
|
62
84
|
|
63
85
|
PLATFORMS
|
64
86
|
ruby
|
@@ -68,8 +90,8 @@ DEPENDENCIES
|
|
68
90
|
filterable-by!
|
69
91
|
rake
|
70
92
|
rspec
|
71
|
-
rubocop
|
93
|
+
rubocop-bsm
|
72
94
|
sqlite3
|
73
95
|
|
74
96
|
BUNDLED WITH
|
75
|
-
1.
|
97
|
+
2.1.4
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015-2018 Black Square Media
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -16,47 +16,33 @@ class Comment < ActiveRecord::Base
|
|
16
16
|
|
17
17
|
filterable_by :post_id, :user_id
|
18
18
|
filterable_by :post_author_id do |scope, value|
|
19
|
-
scope.joins(:posts).where(:
|
19
|
+
scope.joins(:posts).where(:'posts.author_id' => value)
|
20
|
+
end
|
21
|
+
filterable_by :only do |scope, value, **opts|
|
22
|
+
case value
|
23
|
+
when 'mine'
|
24
|
+
scope.where(user_id: opts[:user_id]) if opts[:user_id]
|
25
|
+
else
|
26
|
+
scope
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
23
|
-
Comment.filter_by(params[:filter]) # => ActiveRecord::Relation
|
31
|
+
Comment.filter_by(params[:filter], user_id: current_user.id) # => ActiveRecord::Relation
|
24
32
|
```
|
25
33
|
|
26
34
|
Simple use cases:
|
27
35
|
|
28
36
|
```ruby
|
29
|
-
Comment.filter_by({
|
37
|
+
Comment.filter_by({ 'post_id' => '1' })
|
30
38
|
# => WHERE post_id = 1
|
31
39
|
|
32
|
-
Comment.filter_by({
|
40
|
+
Comment.filter_by({ 'user_id' => '2', 'ignored' => '3' })
|
33
41
|
# => WHERE user_id = 2
|
34
42
|
|
35
|
-
Comment.filter_by({
|
36
|
-
# =>
|
37
|
-
```
|
38
|
-
|
39
|
-
## LICENCE
|
43
|
+
Comment.filter_by({ 'only' => 'mine' }, user_id: 4)
|
44
|
+
# => WHERE user_id = 4
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
45
|
-
a copy of this software and associated documentation files (the
|
46
|
-
"Software"), to deal in the Software without restriction, including
|
47
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
48
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
49
|
-
permit persons to whom the Software is furnished to do so, subject to
|
50
|
-
the following conditions:
|
51
|
-
|
52
|
-
The above copyright notice and this permission notice shall be
|
53
|
-
included in all copies or substantial portions of the Software.
|
54
|
-
|
55
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
56
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
57
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
58
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
59
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
60
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
61
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
46
|
+
Comment.filter_by({ 'post_author_id' => '5' })
|
47
|
+
# => JOINS posts ON posts.id = comments.post_id WHERE posts.author_id = 5
|
62
48
|
```
|
data/Rakefile
CHANGED
data/filterable-by.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
Gem::Specification.new do |s|
|
3
2
|
s.name = 'filterable-by'
|
4
|
-
s.version = '0.
|
3
|
+
s.version = '0.5.2'
|
5
4
|
s.authors = ['Dimitrij Denissenko']
|
6
5
|
s.email = ['dimitrij@blacksquaremedia.com']
|
7
6
|
s.summary = 'Generate white-listed filter scopes from URL parameter values'
|
@@ -9,17 +8,17 @@ Gem::Specification.new do |s|
|
|
9
8
|
s.homepage = 'https://github.com/bsm/filterable-by'
|
10
9
|
s.license = 'MIT'
|
11
10
|
|
12
|
-
s.files = `git ls-files -z`.split("\x0").reject {
|
11
|
+
s.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^spec/}) }
|
13
12
|
s.test_files = `git ls-files -z -- spec/*`.split("\x0")
|
14
13
|
s.require_paths = ['lib']
|
15
|
-
s.required_ruby_version = '>=
|
14
|
+
s.required_ruby_version = '>= 2.6'
|
16
15
|
|
17
|
-
s.add_dependency 'activesupport'
|
18
16
|
s.add_dependency 'activerecord'
|
17
|
+
s.add_dependency 'activesupport'
|
19
18
|
|
20
19
|
s.add_development_dependency 'bundler'
|
21
20
|
s.add_development_dependency 'rake'
|
22
21
|
s.add_development_dependency 'rspec'
|
23
|
-
s.add_development_dependency 'rubocop'
|
22
|
+
s.add_development_dependency 'rubocop-bsm'
|
24
23
|
s.add_development_dependency 'sqlite3'
|
25
24
|
end
|
data/lib/filterable_by.rb
CHANGED
@@ -3,43 +3,59 @@ require 'active_support/concern'
|
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
module FilterableBy
|
7
|
+
def self.normalize(value)
|
8
|
+
case value
|
9
|
+
when String, Numeric
|
10
|
+
value
|
11
|
+
when Array
|
12
|
+
value.select {|v| normalize(v) }
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
16
|
module ClassMethods
|
17
|
+
def self.extended(base) # :nodoc:
|
18
|
+
base.class_attribute :_filterable_by_config, instance_accessor: false, instance_predicate: false
|
19
|
+
base._filterable_by_config = {}
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def inherited(base) # :nodoc:
|
24
|
+
base._filterable_by_config = _filterable_by_config.deep_dup
|
25
|
+
super
|
26
|
+
end
|
15
27
|
|
16
28
|
def filterable_by(*names, &block)
|
17
29
|
names.each do |name|
|
18
|
-
|
30
|
+
_filterable_by_config[name.to_s] = block || ->(scope, value, **) { scope.where(name.to_sym => value) }
|
19
31
|
end
|
20
32
|
end
|
21
33
|
|
22
34
|
# @param [Hash] hash the filter params
|
23
35
|
# @return [ActiveRecord::Relation] the scoped relation
|
24
|
-
def filter_by(hash)
|
36
|
+
def filter_by(hash = nil, **opts)
|
37
|
+
if hash.nil?
|
38
|
+
hash = opts
|
39
|
+
opts = {}
|
40
|
+
end
|
25
41
|
scope = all
|
26
42
|
return scope unless hash.is_a?(Hash)
|
27
43
|
|
28
|
-
|
44
|
+
_filterable_by_config.each do |name, block|
|
29
45
|
next unless hash.key?(name)
|
30
46
|
|
31
|
-
value = hash[name]
|
32
|
-
next
|
47
|
+
value = FilterableBy.normalize(hash[name])
|
48
|
+
next if value.blank?
|
33
49
|
|
34
|
-
scope = block.call(scope, value)
|
50
|
+
scope = block.call(scope, value, **opts)
|
35
51
|
end
|
36
|
-
scope
|
37
|
-
end
|
38
52
|
|
53
|
+
scope || none
|
54
|
+
end
|
39
55
|
end
|
40
56
|
end
|
41
57
|
|
42
58
|
class Base
|
43
|
-
|
59
|
+
extend FilterableBy::ClassMethods
|
44
60
|
end
|
45
61
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::FilterableBy do
|
4
|
+
let(:alice) { AUTHORS[:alice] }
|
5
|
+
let(:bob) { AUTHORS[:bob] }
|
6
|
+
|
7
|
+
let(:apost) { POSTS[:alices] }
|
8
|
+
let(:bpost) { POSTS[:bobs] }
|
9
|
+
|
10
|
+
it 'has config' do
|
11
|
+
expect(Comment.send(:_filterable_by_config).count).to eq(3)
|
12
|
+
expect(Rating.send(:_filterable_by_config).count).to eq(2)
|
13
|
+
expect(Post.send(:_filterable_by_config).count).to eq(2)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'ignores bad inputs' do
|
17
|
+
expect(Comment.filter_by.count).to eq(4)
|
18
|
+
expect(Comment.filter_by(nil).count).to eq(4)
|
19
|
+
expect(Comment.filter_by(nil, extra: true).count).to eq(4)
|
20
|
+
expect(Comment.filter_by('bad').count).to eq(4)
|
21
|
+
|
22
|
+
expect(Comment.filter_by('author_id' => '').count).to eq(4)
|
23
|
+
expect(Comment.filter_by('author_id' => []).count).to eq(4)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'generates simple scopes' do
|
27
|
+
expect(Comment.filter_by('author_id' => alice.id).pluck(:title)).to match_array(%w[AA AB])
|
28
|
+
expect(Comment.filter_by('author_id' => bob.id).pluck(:title)).to match_array(%w[BA BB])
|
29
|
+
expect(Comment.filter_by('author_id' => [alice.id, '']).pluck(:title)).to match_array(%w[AA AB])
|
30
|
+
|
31
|
+
expect(Comment.filter_by('post_id' => apost.id).pluck(:title)).to match_array(%w[AA BA])
|
32
|
+
expect(Comment.filter_by('post_id' => bpost.id).pluck(:title)).to match_array(%w[AB BB])
|
33
|
+
|
34
|
+
expect(Comment.filter_by('post_author_id' => alice.id).pluck(:title)).to match_array(%w[AA BA])
|
35
|
+
expect(Comment.filter_by('post_author_id' => bob.id).pluck(:title)).to match_array(%w[AB BB])
|
36
|
+
|
37
|
+
expect(Rating.filter_by('author_id' => alice.id).count).to eq(0)
|
38
|
+
expect(Rating.filter_by('author_id' => bob.id).count).to eq(1)
|
39
|
+
|
40
|
+
expect(Post.filter_by('author_id' => bob.id).count).to eq(1)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'generates combined scopes' do
|
44
|
+
expect(Comment.filter_by('author_id' => alice.id, 'post_id' => apost.id).pluck(:title)).to match_array(['AA'])
|
45
|
+
expect(Comment.filter_by('author_id' => alice.id, 'post_id' => bpost.id).pluck(:title)).to match_array(['AB'])
|
46
|
+
expect(Comment.filter_by('author_id' => bob.id, 'post_id' => apost.id).pluck(:title)).to match_array(['BA'])
|
47
|
+
expect(Comment.filter_by('author_id' => bob.id, 'post_id' => bpost.id).pluck(:title)).to match_array(['BB'])
|
48
|
+
|
49
|
+
scope = Comment.filter_by('author_id' => [alice.id, bob.id], 'post_id' => bpost.id)
|
50
|
+
expect(scope.pluck(:title)).to match_array(%w[AB BB])
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'combines with other scopes' do
|
54
|
+
scope = Comment.where(author_id: alice.id).filter_by('post_id' => apost.id)
|
55
|
+
expect(scope.pluck(:title)).to match_array(['AA'])
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows custom options' do
|
59
|
+
scope = Post.filter_by({ 'only' => 'me' }, user_id: alice.id)
|
60
|
+
expect(scope).to match_array([apost])
|
61
|
+
|
62
|
+
scope = Post.filter_by({ 'only' => '??' }, user_id: alice.id)
|
63
|
+
expect(scope.count).to eq(2)
|
64
|
+
|
65
|
+
scope = Post.filter_by({ 'only' => 'me' })
|
66
|
+
expect(scope.count).to eq(0)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'allows custom options from params' do
|
70
|
+
filter = { 'only' => 'me' }
|
71
|
+
expect(Post.filter_by(filter, user_id: alice.id)).to match_array([apost])
|
72
|
+
expect(Post.filter_by(filter).count).to eq(0)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'ignores invalid scopes' do
|
76
|
+
expect(Comment.filter_by('invalid' => 1).count).to eq(4)
|
77
|
+
expect(Post.filter_by('post_id' => bpost.id).count).to eq(2)
|
78
|
+
expect(Rating.filter_by('post_author_id' => bob.id).count).to eq(1)
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,17 +2,20 @@ ENV['RACK_ENV'] ||= 'test'
|
|
2
2
|
require 'filterable-by'
|
3
3
|
require 'rspec'
|
4
4
|
|
5
|
-
ActiveRecord::Base.configurations
|
5
|
+
ActiveRecord::Base.configurations = { 'test' => { 'adapter' => 'sqlite3', 'database' => ':memory:' } }
|
6
6
|
ActiveRecord::Base.establish_connection :test
|
7
7
|
|
8
8
|
ActiveRecord::Base.connection.instance_eval do
|
9
9
|
create_table :authors do |_|
|
10
|
+
# no columns
|
10
11
|
end
|
11
12
|
create_table :posts do |t|
|
12
13
|
t.integer :author_id, null: false
|
13
14
|
end
|
14
|
-
create_table :
|
15
|
-
t.string :
|
15
|
+
create_table :feedbacks do |t|
|
16
|
+
t.string :type, null: false
|
17
|
+
t.string :title
|
18
|
+
t.integer :stars, null: false, default: 0
|
16
19
|
t.integer :post_id, null: false
|
17
20
|
t.integer :author_id, null: false
|
18
21
|
end
|
@@ -23,31 +26,48 @@ end
|
|
23
26
|
|
24
27
|
class Post < ActiveRecord::Base
|
25
28
|
belongs_to :author
|
29
|
+
|
30
|
+
filterable_by :author_id
|
31
|
+
filterable_by :only do |scope, value, **opts|
|
32
|
+
case value
|
33
|
+
when 'me'
|
34
|
+
scope.where(author_id: opts[:user_id]) if opts[:user_id]
|
35
|
+
else
|
36
|
+
scope
|
37
|
+
end
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
|
-
class
|
41
|
+
class Feedback < ActiveRecord::Base
|
29
42
|
belongs_to :author
|
30
43
|
belongs_to :post
|
31
44
|
|
32
45
|
filterable_by :post_id, :author_id
|
46
|
+
end
|
47
|
+
|
48
|
+
class Comment < Feedback
|
33
49
|
filterable_by :post_author_id do |scope, value|
|
34
50
|
scope.joins(:post).where(Post.arel_table[:author_id].eq(value))
|
35
51
|
end
|
36
52
|
end
|
37
53
|
|
54
|
+
class Rating < Feedback
|
55
|
+
end
|
56
|
+
|
38
57
|
AUTHORS = {
|
39
58
|
alice: Author.create!,
|
40
|
-
bob:
|
41
|
-
}
|
59
|
+
bob: Author.create!,
|
60
|
+
}.freeze
|
42
61
|
|
43
62
|
POSTS = {
|
44
63
|
alices: Post.create!(author_id: AUTHORS[:alice].id),
|
45
|
-
bobs:
|
46
|
-
}
|
64
|
+
bobs: Post.create!(author_id: AUTHORS[:bob].id),
|
65
|
+
}.freeze
|
47
66
|
|
48
67
|
COMMENTS = {
|
49
68
|
alice_on_alice: Comment.create!(title: 'AA', post_id: POSTS[:alices].id, author_id: AUTHORS[:alice].id),
|
50
|
-
bob_on_alice:
|
51
|
-
alice_on_bob:
|
52
|
-
bob_on_bob:
|
53
|
-
|
69
|
+
bob_on_alice: Comment.create!(title: 'BA', post_id: POSTS[:alices].id, author_id: AUTHORS[:bob].id),
|
70
|
+
alice_on_bob: Comment.create!(title: 'AB', post_id: POSTS[:bobs].id, author_id: AUTHORS[:alice].id),
|
71
|
+
bob_on_bob: Comment.create!(title: 'BB', post_id: POSTS[:bobs].id, author_id: AUTHORS[:bob].id),
|
72
|
+
boa_rating: Rating.create!(stars: 5, post_id: POSTS[:alices].id, author_id: AUTHORS[:bob].id),
|
73
|
+
}.freeze
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filterable-by
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitrij Denissenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
84
|
+
name: rubocop-bsm
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -115,18 +115,18 @@ executables: []
|
|
115
115
|
extensions: []
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
|
+
- ".github/workflows/ruby.yml"
|
118
119
|
- ".gitignore"
|
119
120
|
- ".rubocop.yml"
|
120
|
-
- ".rubocop_todo.yml"
|
121
|
-
- ".travis.yml"
|
122
121
|
- Gemfile
|
123
122
|
- Gemfile.lock
|
123
|
+
- LICENSE
|
124
124
|
- README.md
|
125
125
|
- Rakefile
|
126
126
|
- filterable-by.gemspec
|
127
127
|
- lib/filterable-by.rb
|
128
128
|
- lib/filterable_by.rb
|
129
|
-
- spec/filterable_by_spec.rb
|
129
|
+
- spec/active_record/filterable_by_spec.rb
|
130
130
|
- spec/spec_helper.rb
|
131
131
|
homepage: https://github.com/bsm/filterable-by
|
132
132
|
licenses:
|
@@ -140,18 +140,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
140
|
requirements:
|
141
141
|
- - ">="
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
143
|
+
version: '2.6'
|
144
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
145
|
requirements:
|
146
146
|
- - ">="
|
147
147
|
- !ruby/object:Gem::Version
|
148
148
|
version: '0'
|
149
149
|
requirements: []
|
150
|
-
|
151
|
-
rubygems_version: 2.4.7
|
150
|
+
rubygems_version: 3.1.4
|
152
151
|
signing_key:
|
153
152
|
specification_version: 4
|
154
153
|
summary: Generate white-listed filter scopes from URL parameter values
|
155
154
|
test_files:
|
156
|
-
- spec/filterable_by_spec.rb
|
155
|
+
- spec/active_record/filterable_by_spec.rb
|
157
156
|
- spec/spec_helper.rb
|
data/.rubocop_todo.yml
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
-
# on 2015-10-29 12:58:41 +0000 using RuboCop version 0.32.0.
|
3
|
-
# The point is for the user to remove these configuration records
|
4
|
-
# one by one as the offenses are removed from the code base.
|
5
|
-
# Note that changes in the inspected code, or installation of new
|
6
|
-
# versions of RuboCop, may require this file to be generated again.
|
7
|
-
|
8
|
-
# Offense count: 2
|
9
|
-
# Cop supports --auto-correct.
|
10
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
11
|
-
Style/EmptyLinesAroundBlockBody:
|
12
|
-
Enabled: false
|
13
|
-
|
14
|
-
# Offense count: 2
|
15
|
-
# Cop supports --auto-correct.
|
16
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
17
|
-
Style/EmptyLinesAroundModuleBody:
|
18
|
-
Enabled: false
|
19
|
-
|
20
|
-
# Offense count: 1
|
21
|
-
# Configuration parameters: Exclude.
|
22
|
-
Style/FileName:
|
23
|
-
Enabled: false
|
24
|
-
|
25
|
-
# Offense count: 1
|
26
|
-
# Cop supports --auto-correct.
|
27
|
-
Style/SingleSpaceBeforeFirstArg:
|
28
|
-
Enabled: false
|
29
|
-
|
30
|
-
# Offense count: 3
|
31
|
-
# Cop supports --auto-correct.
|
32
|
-
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
33
|
-
Style/TrailingComma:
|
34
|
-
Enabled: false
|
35
|
-
|
36
|
-
# Offense count: 6
|
37
|
-
# Cop supports --auto-correct.
|
38
|
-
# Configuration parameters: WordRegex.
|
39
|
-
Style/WordArray:
|
40
|
-
MinSize: 2
|
data/.travis.yml
DELETED
data/spec/filterable_by_spec.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
describe ActiveRecord::FilterableByHelper do
|
4
|
-
|
5
|
-
let(:alice) { AUTHORS[:alice] }
|
6
|
-
let(:bob) { AUTHORS[:bob] }
|
7
|
-
|
8
|
-
let(:apost) { POSTS[:alices] }
|
9
|
-
let(:bpost) { POSTS[:bobs] }
|
10
|
-
|
11
|
-
it 'should have config' do
|
12
|
-
expect(Comment._filterable_by_scope_options.size).to eq(3)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should ignore bad inputs' do
|
16
|
-
expect(Comment.filter_by(nil).count).to eq(4)
|
17
|
-
expect(Comment.filter_by({}).count).to eq(4)
|
18
|
-
|
19
|
-
expect(Comment.filter_by('author_id' => '').count).to eq(4)
|
20
|
-
expect(Comment.filter_by('author_id' => []).count).to eq(4)
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should generate simple scopes' do
|
24
|
-
expect(Comment.filter_by('author_id' => alice.id).pluck(:title)).to match_array(['AA', 'AB'])
|
25
|
-
expect(Comment.filter_by('author_id' => bob.id).pluck(:title)).to match_array(['BA', 'BB'])
|
26
|
-
|
27
|
-
expect(Comment.filter_by('post_id' => apost.id).pluck(:title)).to match_array(['AA', 'BA'])
|
28
|
-
expect(Comment.filter_by('post_id' => bpost.id).pluck(:title)).to match_array(['AB', 'BB'])
|
29
|
-
|
30
|
-
expect(Comment.filter_by('post_author_id' => alice.id).pluck(:title)).to match_array(['AA', 'BA'])
|
31
|
-
expect(Comment.filter_by('post_author_id' => bob.id).pluck(:title)).to match_array(['AB', 'BB'])
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should generate combined scopes' do
|
35
|
-
expect(Comment.filter_by('author_id' => alice.id, 'post_id' => apost.id).pluck(:title)).to match_array(['AA'])
|
36
|
-
expect(Comment.filter_by('author_id' => alice.id, 'post_id' => bpost.id).pluck(:title)).to match_array(['AB'])
|
37
|
-
expect(Comment.filter_by('author_id' => bob.id, 'post_id' => apost.id).pluck(:title)).to match_array(['BA'])
|
38
|
-
expect(Comment.filter_by('author_id' => bob.id, 'post_id' => bpost.id).pluck(:title)).to match_array(['BB'])
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'should combine with other scopes' do
|
42
|
-
scope = Comment.where(author_id: alice.id).filter_by('post_id' => apost.id)
|
43
|
-
expect(scope.pluck(:title)).to match_array(['AA'])
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|