filterrific 5.2.3 → 5.2.5
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +3 -3
- data/Rakefile +7 -7
- data/app/assets/javascripts/filterrific/filterrific.js +172 -0
- data/lib/filterrific/action_controller_extension.rb +14 -17
- data/lib/filterrific/action_view_extension.rb +35 -34
- data/lib/filterrific/active_record_extension.rb +6 -10
- data/lib/filterrific/engine.rb +5 -9
- data/lib/filterrific/has_reset_filterrific_url_mixin.rb +1 -4
- data/lib/filterrific/param_set.rb +18 -26
- data/lib/filterrific/version.rb +1 -3
- data/lib/filterrific.rb +2 -4
- data/spec/filterrific/action_controller_extension_spec.rb +78 -80
- data/spec/filterrific/action_view_extension_spec.rb +9 -12
- data/spec/filterrific/active_record_extension_spec.rb +24 -38
- data/spec/filterrific/param_set_spec.rb +89 -109
- data/spec/filterrific_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -5
- metadata +3 -3
- data/app/assets/javascripts/filterrific/filterrific-jquery.js +0 -118
@@ -1,13 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_support/all'
|
4
|
-
require 'digest/sha1'
|
1
|
+
require "active_support/all"
|
2
|
+
require "digest/sha1"
|
5
3
|
|
6
4
|
module Filterrific
|
7
|
-
|
8
5
|
# FilterParamSet is a container to store FilterParams
|
9
6
|
class ParamSet
|
10
|
-
|
11
7
|
attr_accessor :model_class
|
12
8
|
attr_accessor :select_options
|
13
9
|
|
@@ -27,16 +23,16 @@ module Filterrific
|
|
27
23
|
# You might wonder "what if I want to change only one thing from the defaults?"
|
28
24
|
# Persistence, baby. By the time you submit changes to one filter, all the others
|
29
25
|
# will be already initialized with the defaults.
|
30
|
-
filterrific_params = model_class.filterrific_default_filter_params
|
26
|
+
filterrific_params = model_class.filterrific_default_filter_params if filterrific_params.blank?
|
31
27
|
if defined?(ActionController::Parameters) && filterrific_params.is_a?(ActionController::Parameters)
|
32
28
|
permissible_filter_params = []
|
33
29
|
model_class.filterrific_available_filters.each do |p|
|
34
|
-
if filterrific_params[p].is_a?(ActionController::Parameters)
|
35
|
-
|
30
|
+
permissible_filter_params << if filterrific_params[p].is_a?(ActionController::Parameters)
|
31
|
+
{p => filterrific_params[p].keys}
|
36
32
|
elsif filterrific_params[p].is_a?(Array)
|
37
|
-
|
33
|
+
{p => []}
|
38
34
|
else
|
39
|
-
|
35
|
+
p
|
40
36
|
end
|
41
37
|
end
|
42
38
|
filterrific_params = filterrific_params.permit(permissible_filter_params).to_h.stringify_keys
|
@@ -60,14 +56,13 @@ module Filterrific
|
|
60
56
|
def to_hash
|
61
57
|
{}.tap { |h|
|
62
58
|
model_class.filterrific_available_filters.each do |filter_name|
|
63
|
-
param_value =
|
64
|
-
|
65
|
-
when param_value.blank?
|
59
|
+
param_value = send(filter_name)
|
60
|
+
if param_value.blank?
|
66
61
|
# do nothing
|
67
|
-
|
62
|
+
elsif param_value.is_a?(Proc)
|
68
63
|
# evaluate Proc so it can be serialized
|
69
64
|
h[filter_name] = param_value.call
|
70
|
-
|
65
|
+
elsif param_value.is_a?(OpenStruct)
|
71
66
|
# convert OpenStruct to hash
|
72
67
|
h[filter_name] = param_value.marshal_dump
|
73
68
|
else
|
@@ -83,25 +78,24 @@ module Filterrific
|
|
83
78
|
to_hash.to_json
|
84
79
|
end
|
85
80
|
|
86
|
-
|
81
|
+
protected
|
87
82
|
|
88
83
|
# Conditions params: Evaluates Procs and type casts integer values.
|
89
84
|
# @param fp [Hash] the filterrific params hash
|
90
85
|
# @return[Hash] the conditioned params hash
|
91
86
|
def condition_filterrific_params(fp)
|
92
87
|
fp.each do |key, val|
|
93
|
-
|
94
|
-
when val.is_a?(Proc)
|
88
|
+
if val.is_a?(Proc)
|
95
89
|
# evaluate Procs
|
96
90
|
fp[key] = val.call
|
97
|
-
|
91
|
+
elsif val.is_a?(Array)
|
98
92
|
# type cast integers in the array
|
99
|
-
fp[key] = fp[key].map { |e| e
|
100
|
-
|
93
|
+
fp[key] = fp[key].map { |e| e.to_s.match?(integer_detector_regex) ? e.to_i : e }
|
94
|
+
elsif val.is_a?(Hash)
|
101
95
|
# type cast Hash to OpenStruct so that nested params render correctly
|
102
96
|
# in the form
|
103
97
|
fp[key] = OpenStruct.new(fp[key])
|
104
|
-
|
98
|
+
elsif val.is_a?(String) && val.match?(integer_detector_regex)
|
105
99
|
# type cast integer
|
106
100
|
fp[key] = fp[key].to_i
|
107
101
|
end
|
@@ -121,10 +115,8 @@ module Filterrific
|
|
121
115
|
model_class.filterrific_available_filters.each do |filter_name|
|
122
116
|
self.class.send(:attr_accessor, filter_name)
|
123
117
|
v = fp[filter_name]
|
124
|
-
|
118
|
+
send("#{filter_name}=", v) if v.present?
|
125
119
|
end
|
126
120
|
end
|
127
|
-
|
128
121
|
end
|
129
|
-
|
130
122
|
end
|
data/lib/filterrific/version.rb
CHANGED
data/lib/filterrific.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
if ![5,6,7].include?(Rails::VERSION::MAJOR)
|
4
2
|
raise "\n\nThis version of Filterrific only works with Rails 5, 6 and 7.\nPlease see the Filterrific README for the correct version of Filterrific to use with your version of Rails!\n\n"
|
5
3
|
end
|
6
4
|
|
7
|
-
require
|
8
|
-
require
|
5
|
+
require "filterrific/version"
|
6
|
+
require "filterrific/engine"
|
9
7
|
|
10
8
|
module Filterrific
|
11
9
|
end
|
@@ -1,80 +1,84 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "filterrific/action_controller_extension"
|
3
|
+
require "action_view/helpers/sanitize_helper"
|
4
4
|
|
5
5
|
module Filterrific
|
6
|
+
class TestController
|
7
|
+
include ActionControllerExtension
|
8
|
+
def action_name
|
9
|
+
"index"
|
10
|
+
end
|
6
11
|
|
7
|
-
|
12
|
+
def controller_name
|
13
|
+
"test_controller"
|
14
|
+
end
|
15
|
+
# In a production app the #helpers method makes Rails helpers available in
|
16
|
+
# a controller instance. For testing our module outside of rails, we just
|
17
|
+
# include the required helpers in the TestController class
|
18
|
+
# and then delegate #helpers to self.
|
19
|
+
include ActionView::Helpers::SanitizeHelper
|
20
|
+
def helpers
|
21
|
+
self
|
22
|
+
end
|
8
23
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# a controller instance. For testing our module outside of rails, we just
|
15
|
-
# include the required helpers in the TestController class
|
16
|
-
# and then delegate #helpers to self.
|
17
|
-
include ActionView::Helpers::SanitizeHelper
|
18
|
-
def helpers; self; end
|
19
|
-
def session
|
20
|
-
{
|
21
|
-
'test_controller#index' => {
|
22
|
-
'filter1' => '1_from_session',
|
23
|
-
'filter2' => '2_from_session',
|
24
|
-
}
|
24
|
+
def session
|
25
|
+
{
|
26
|
+
"test_controller#index" => {
|
27
|
+
"filter1" => "1_from_session",
|
28
|
+
"filter2" => "2_from_session"
|
25
29
|
}
|
26
|
-
|
30
|
+
}
|
27
31
|
end
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
{ 'filter1' => '1_from_model_defaults' }
|
33
|
-
end
|
34
|
+
class TestModelClass
|
35
|
+
def self.filterrific_available_filters
|
36
|
+
%w[filter1 filter2]
|
34
37
|
end
|
35
38
|
|
36
|
-
|
39
|
+
def self.filterrific_default_filter_params
|
40
|
+
{"filter1" => "1_from_model_defaults"}
|
41
|
+
end
|
42
|
+
end
|
37
43
|
|
38
|
-
|
44
|
+
describe ActionControllerExtension do
|
45
|
+
describe "#initialize_filterrific" do
|
46
|
+
it "returns a Filterrific::ParamSet" do
|
39
47
|
TestController.new.send(
|
40
48
|
:initialize_filterrific,
|
41
49
|
TestModelClass,
|
42
|
-
{
|
50
|
+
{"filter1" => 1, "filter2" => 2}
|
43
51
|
).must_be_instance_of(ParamSet)
|
44
52
|
end
|
45
|
-
|
46
53
|
end
|
47
54
|
|
48
|
-
describe
|
49
|
-
|
50
|
-
it 'computes the default persistence id from controller_name and action_name' do
|
55
|
+
describe "#compute_default_persistence_id" do
|
56
|
+
it "computes the default persistence id from controller_name and action_name" do
|
51
57
|
TestController.new.send(
|
52
58
|
:compute_default_persistence_id
|
53
|
-
).must_equal(
|
59
|
+
).must_equal("test_controller#index")
|
54
60
|
end
|
55
|
-
|
56
61
|
end
|
57
62
|
|
58
|
-
describe
|
59
|
-
|
60
|
-
it 'uses filterrific_params if given' do
|
63
|
+
describe "#compute_filterrific_params" do
|
64
|
+
it "uses filterrific_params if given" do
|
61
65
|
TestController.new.send(
|
62
66
|
:compute_filterrific_params,
|
63
67
|
TestModelClass,
|
64
|
-
{
|
65
|
-
{
|
66
|
-
|
67
|
-
).must_equal({
|
68
|
+
{"filter1" => 1, "filter2" => 2},
|
69
|
+
{},
|
70
|
+
"test_controller#index"
|
71
|
+
).must_equal({"filter1" => 1, "filter2" => 2})
|
68
72
|
end
|
69
73
|
|
70
|
-
it
|
74
|
+
it "uses session if filterrific_params are blank" do
|
71
75
|
TestController.new.send(
|
72
76
|
:compute_filterrific_params,
|
73
77
|
TestModelClass,
|
74
78
|
{},
|
75
|
-
{
|
76
|
-
|
77
|
-
).must_equal({
|
79
|
+
{},
|
80
|
+
"test_controller#index"
|
81
|
+
).must_equal({"filter1" => "1_from_session", "filter2" => "2_from_session"})
|
78
82
|
end
|
79
83
|
|
80
84
|
it "uses opts['default_filter_params'] if session is blank" do
|
@@ -82,9 +86,9 @@ module Filterrific
|
|
82
86
|
:compute_filterrific_params,
|
83
87
|
TestModelClass,
|
84
88
|
{},
|
85
|
-
{
|
86
|
-
|
87
|
-
).must_equal({
|
89
|
+
{"default_filter_params" => {"filter1" => "1_from_opts"}},
|
90
|
+
"non existent persistence id to skip session"
|
91
|
+
).must_equal({"filter1" => "1_from_opts"})
|
88
92
|
end
|
89
93
|
|
90
94
|
it "uses model default_filter_params if opts is blank" do
|
@@ -92,72 +96,66 @@ module Filterrific
|
|
92
96
|
:compute_filterrific_params,
|
93
97
|
TestModelClass,
|
94
98
|
{},
|
95
|
-
{
|
96
|
-
|
97
|
-
).must_equal({
|
99
|
+
{},
|
100
|
+
"non existent persistence id to skip session"
|
101
|
+
).must_equal({"filter1" => "1_from_model_defaults"})
|
98
102
|
end
|
99
103
|
|
100
104
|
it "limits filter params to opts['available_filters']" do
|
101
105
|
TestController.new.send(
|
102
106
|
:compute_filterrific_params,
|
103
107
|
TestModelClass,
|
104
|
-
{
|
105
|
-
{
|
106
|
-
|
107
|
-
).must_equal({
|
108
|
+
{"filter1" => 1, "filter2" => 2},
|
109
|
+
{"available_filters" => %w[filter1]},
|
110
|
+
"test_controller#index"
|
111
|
+
).must_equal({"filter1" => 1})
|
108
112
|
end
|
109
113
|
|
110
114
|
it "sanitizes filterrific params by default" do
|
111
115
|
TestController.new.send(
|
112
116
|
:compute_filterrific_params,
|
113
117
|
TestModelClass,
|
114
|
-
{
|
115
|
-
{
|
116
|
-
|
117
|
-
).must_equal({
|
118
|
+
{"filter1" => "1' <script>alert('xss attack!');</script>"},
|
119
|
+
{},
|
120
|
+
"test_controller#index"
|
121
|
+
).must_equal({"filter1" => "1' alert('xss attack!');"})
|
118
122
|
end
|
119
123
|
|
120
124
|
it "sanitizes filterrific Array params" do
|
121
125
|
TestController.new.send(
|
122
126
|
:compute_filterrific_params,
|
123
127
|
TestModelClass,
|
124
|
-
{
|
125
|
-
{
|
126
|
-
|
127
|
-
).must_equal({
|
128
|
+
{"filter1" => ["1' <script>alert('xss attack!');</script>", 3]},
|
129
|
+
{},
|
130
|
+
"test_controller#index"
|
131
|
+
).must_equal({"filter1" => ["1' alert('xss attack!');", 3]})
|
128
132
|
end
|
129
133
|
|
130
134
|
it "sanitizes filterrific Hash params" do
|
131
135
|
TestController.new.send(
|
132
136
|
:compute_filterrific_params,
|
133
137
|
TestModelClass,
|
134
|
-
{
|
135
|
-
{
|
136
|
-
|
137
|
-
).must_equal({
|
138
|
+
{"filter1" => {1 => "1' <script>alert('xss attack!');</script>", 2 => 3}},
|
139
|
+
{},
|
140
|
+
"test_controller#index"
|
141
|
+
).must_equal({"filter1" => {1 => "1' alert('xss attack!');", 2 => 3}})
|
138
142
|
end
|
139
143
|
|
140
144
|
it "skips param sanitization if told so via options" do
|
141
145
|
TestController.new.send(
|
142
146
|
:compute_filterrific_params,
|
143
147
|
TestModelClass,
|
144
|
-
{
|
145
|
-
{
|
146
|
-
|
147
|
-
).must_equal({
|
148
|
+
{"filter1" => "1' <script>alert('xss attack!');</script>"},
|
149
|
+
{sanitize_params: false},
|
150
|
+
"test_controller#index"
|
151
|
+
).must_equal({"filter1" => "1' <script>alert('xss attack!');</script>"})
|
148
152
|
end
|
149
|
-
|
150
153
|
end
|
151
154
|
|
152
|
-
describe
|
153
|
-
|
154
|
-
it 'responds to #reset_filterrific_url' do
|
155
|
+
describe "#reset_filterrific_url" do
|
156
|
+
it "responds to #reset_filterrific_url" do
|
155
157
|
TestController.new.must_respond_to(:reset_filterrific_url)
|
156
158
|
end
|
157
|
-
|
158
159
|
end
|
159
|
-
|
160
160
|
end
|
161
161
|
end
|
162
|
-
|
163
|
-
|
@@ -1,29 +1,26 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "filterrific/action_view_extension"
|
3
3
|
|
4
4
|
module Filterrific
|
5
|
+
class ViewContext
|
6
|
+
include ActionViewExtension
|
7
|
+
end
|
5
8
|
|
6
9
|
describe ActionViewExtension do
|
7
|
-
|
8
|
-
class ViewContext
|
9
|
-
include ActionViewExtension
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'responds to #form_for_filterrific' do
|
10
|
+
it "responds to #form_for_filterrific" do
|
13
11
|
ViewContext.new.must_respond_to(:form_for_filterrific)
|
14
12
|
end
|
15
13
|
|
16
|
-
it
|
14
|
+
it "responds to #render_filterrific_spinner" do
|
17
15
|
ViewContext.new.must_respond_to(:render_filterrific_spinner)
|
18
16
|
end
|
19
17
|
|
20
|
-
it
|
18
|
+
it "responds to #filterrific_sorting_link" do
|
21
19
|
ViewContext.new.must_respond_to(:filterrific_sorting_link)
|
22
20
|
end
|
23
21
|
|
24
|
-
it
|
22
|
+
it "responds to #reset_filterrific_url" do
|
25
23
|
ViewContext.new.must_respond_to(:reset_filterrific_url)
|
26
24
|
end
|
27
|
-
|
28
25
|
end
|
29
26
|
end
|
@@ -1,27 +1,23 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "active_record"
|
3
|
+
require "filterrific/active_record_extension"
|
4
4
|
|
5
5
|
ActiveRecord::Base.extend Filterrific::ActiveRecordExtension
|
6
6
|
|
7
7
|
module Filterrific
|
8
|
+
# Container for test data
|
9
|
+
class TestDataARES
|
10
|
+
def self.filterrific_available_filters
|
11
|
+
%w[search_query sorted_by with_country_id]
|
12
|
+
end
|
8
13
|
|
9
|
-
|
10
|
-
|
11
|
-
# Container for test data
|
12
|
-
class TestDataARES
|
13
|
-
|
14
|
-
def self.filterrific_available_filters
|
15
|
-
%w[search_query sorted_by with_country_id]
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.filterrific_default_filter_params
|
19
|
-
{ 'sorted_by' => 'name_asc' }
|
20
|
-
end
|
21
|
-
|
14
|
+
def self.filterrific_default_filter_params
|
15
|
+
{"sorted_by" => "name_asc"}
|
22
16
|
end
|
17
|
+
end
|
23
18
|
|
24
|
-
|
19
|
+
describe ActiveRecordExtension do
|
20
|
+
let(:filterrific_class) {
|
25
21
|
Class.new(ActiveRecord::Base) do
|
26
22
|
filterrific(
|
27
23
|
available_filters: TestDataARES.filterrific_available_filters,
|
@@ -31,7 +27,6 @@ module Filterrific
|
|
31
27
|
}
|
32
28
|
|
33
29
|
describe "Class method extensions" do
|
34
|
-
|
35
30
|
it "adds a 'filterrific' class method" do
|
36
31
|
filterrific_class.must_respond_to(:filterrific)
|
37
32
|
end
|
@@ -39,11 +34,9 @@ module Filterrific
|
|
39
34
|
it "adds a 'filterrific_find' class method" do
|
40
35
|
filterrific_class.must_respond_to(:filterrific_find)
|
41
36
|
end
|
42
|
-
|
43
37
|
end
|
44
38
|
|
45
39
|
describe "Filterrific initialization" do
|
46
|
-
|
47
40
|
it "initializes filterrific_available_filters" do
|
48
41
|
filterrific_class.filterrific_available_filters.must_equal(
|
49
42
|
TestDataARES.filterrific_available_filters
|
@@ -71,44 +64,37 @@ module Filterrific
|
|
71
64
|
Class.new(ActiveRecord::Base) do
|
72
65
|
filterrific(
|
73
66
|
available_filters: [:one, :two],
|
74
|
-
default_filter_params:{
|
67
|
+
default_filter_params: {three: ""}
|
75
68
|
)
|
76
69
|
end
|
77
70
|
}.must_raise(ArgumentError)
|
78
71
|
end
|
79
|
-
|
80
72
|
end
|
81
73
|
|
82
74
|
describe "filterrific_find" do
|
83
|
-
|
84
75
|
it "raises when given invalid params" do
|
85
76
|
proc {
|
86
|
-
filterrific_class.filterrific_find(
|
77
|
+
filterrific_class.filterrific_find("an invalid argument")
|
87
78
|
}.must_raise(ArgumentError)
|
88
79
|
end
|
89
|
-
|
90
80
|
end
|
91
|
-
|
92
81
|
end
|
93
82
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
filterrific(available_filters: [:one, :two])
|
98
|
-
end
|
83
|
+
class Daddy < ActiveRecord::Base
|
84
|
+
filterrific(available_filters: [:one, :two])
|
85
|
+
end
|
99
86
|
|
100
|
-
|
101
|
-
|
102
|
-
|
87
|
+
class Girl < Daddy
|
88
|
+
filterrific(available_filters: [:three, :four])
|
89
|
+
end
|
103
90
|
|
104
|
-
|
91
|
+
describe "Single Table Inheritance" do
|
92
|
+
%w[one two].each do |value|
|
105
93
|
it { Daddy.filterrific_available_filters.must_include value }
|
106
94
|
end
|
107
95
|
|
108
|
-
%w
|
96
|
+
%w[three four].each do |value|
|
109
97
|
it { Girl.filterrific_available_filters.must_include value }
|
110
98
|
end
|
111
|
-
|
112
99
|
end
|
113
|
-
|
114
100
|
end
|