filterrific 1.4.3 → 2.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dfb96075da4c30641cdfb5fdf747706a310f0324
4
- data.tar.gz: fc4f107545fa2838949eb88be2b0beee14927d14
3
+ metadata.gz: 5771d0552efaa97955d18305f8199f7691148d93
4
+ data.tar.gz: 037e7d5b634f6183cd6315d35cdd5a8874c47f3c
5
5
  SHA512:
6
- metadata.gz: 32d36a46d02d7fd55951b41c05e54022696dcccee1cb184fdf6da63bf469104e8279141a7fd620a4dbb49a24c8f579a58a4646963ef632f3672f75c8478d95b2
7
- data.tar.gz: 1d427b2a134182022656d1ef5cc3347e2c3f05d9fdcb4bb81cb8d8ad15a1f0cac7e6266f73670dd979df1afa30433e4ba93ca1ef380837a41ef4f79fa6f0c372
6
+ metadata.gz: 6da890161d37d8884debfff82b057f1fe304ebcf858b6a0493cc756739428cc33fdc131abd0f174fd4ea449704404adc10204c33fa22d89b96c623001aefdafc
7
+ data.tar.gz: 192de17ea6192932f6e6c262fa6888fa35b39188ec0c99dcaf76bedd94434671f2754968ac4e9cc0fad8d2fc461c95dbb122e1b11074afc7fe1567b46920258d
data/CHANGELOG.md CHANGED
@@ -1,12 +1,10 @@
1
- # 2.0.0
2
-
3
- API changes
4
-
5
- * Filterrific can build the `sorted_by` and `search_query` scopes automatically,
6
- based on some configuration in the including model.
7
-
1
+ * using the "sorted_by" magic method will add entries to select_options automatically
8
2
  filterrific(
9
- default_settings: { sorted_by: 'name_asc' },
3
+ default_filter_params: { sorted_by: 'name_asc' },
4
+ available_filters: [
5
+ :with_country,
6
+ ...
7
+ ],
10
8
  search_query: {
11
9
  match_terms: :any, # [:all]
12
10
  auto_wildcard: :suffix, # [:prefix, :both, :none]
@@ -17,39 +15,56 @@ API changes
17
15
  name_asc: 'Name (A-Z)',
18
16
  name_desc: 'Name (Z-A)',
19
17
  },
20
- scopes: [
18
+ )
19
+
20
+ filterrific(
21
+ default_filter_params: { sorted_by: 'name_asc' },
22
+ custom_scopes: [
21
23
  :with_country,
22
24
  ...
25
+ ],
26
+ lookup_filters: [ # column_value_filters:, value_filters:
27
+ :with_country_id,
28
+ :with_state,
23
29
  ]
30
+ search_query: {
31
+ match_terms: :any, # [:all]
32
+ auto_wildcard: :suffix, # [:prefix, :both, :none]
33
+ columns: [:first_name, :email, :last_name],
34
+ case_sensitive: false, # [true]
35
+ },
36
+ sorted_by: {
37
+ name_asc: 'Name (A-Z)',
38
+ name_desc: 'Name (Z-A)',
39
+ },
24
40
  )
25
41
 
26
- * Filterrific can handle persistence of search params in session for you.
27
- * Simplified `@filterrific.find` method to load collection from DB.
28
- Replaces `Student.filterrific_find(@filterrific)`
29
42
 
30
- @filterrific = initialize_filterrific(
31
- Student,
32
- default_settings: {},
33
- filter_names: [],
34
- params_key: :filterrific,
35
- select_options: {},
36
- session_persistence_key: 'asdf',
37
- )
38
- @students = @filterrific.find
39
43
 
40
- * The filterrific form builder now doesn't override the standard
41
- `form_for` method. It is used via `form_for_filterrific` instead:
44
+ # 2.0.0
42
45
 
43
- form_for_filterrific @filterrific do |f|
46
+ API changes:
44
47
 
48
+ * Filterrific model API option names have changed.
49
+ * Better initialization of Filterrific via `initialize_filterrific` method:
50
+ * It resets the filter params, so the `reset_filterrific` action is not required any more.
51
+ * It persists filter params in session.
52
+ * Simplified `@filterrific.find` method to load collection from DB.
53
+ Replaces `Student.filterrific_find(@filterrific)`
54
+ * The `form_for_filterrific` form builder doesn't override the standard
55
+ `form_for` method any more.
45
56
  * Dropped support for Ruby 1.8.7 (because of 1.9 Hash syntax)
46
57
  * Dropped support for Rails <= 3.0.0 (because of ActiveRecord
47
58
  bug fixes in 3.1, and use of asset pipeline)
48
59
 
60
+
61
+
49
62
  ### 1.4.3
50
63
 
51
64
  * Handle case where Filterrific filter params are empty.
52
65
 
66
+
67
+
53
68
  ### 1.4.2
54
69
 
55
70
  * Updated initialization of ActiveRecord and ActionView extensions again
data/README.md CHANGED
@@ -13,8 +13,6 @@ search, and sort your ActiveRecord lists:
13
13
  Make sure to go to the fantastic [Filterrific documentation](http://filterrific.clearcove.ca)
14
14
  to find out more!
15
15
 
16
- TODO: look at Jeff's email suggestions (June 23, 2014)
17
-
18
16
  ### Installation
19
17
 
20
18
  `gem install filterrific`
@@ -28,11 +26,11 @@ or with bundler in your Gemfile:
28
26
 
29
27
  Every commit to Filterrific is automatically tested against the following scenarios:
30
28
 
31
- | Rails version | Ruby environments | Database adapters | Build status |
32
- |---------------|-------------------------|------------------------------------|--------------|
33
- | Rails 4.1 | MRI 1.9.3, 2.0.0, 2.1.2 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-4.1)](https://travis-ci.org/jhund/filterrific_demo)|
34
- | Rails 4.0 | MRI 1.9.3, 2.0.0, 2.1.2 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-4.0)](https://travis-ci.org/jhund/filterrific_demo)|
35
- | Rails 3.2 | MRI 1.9.3, 2.0.0, 2.1.2 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-3.2)](https://travis-ci.org/jhund/filterrific_demo)|
29
+ | Rails version | Ruby environments | Database adapters | Build status |
30
+ |---------------|--------------------------------|------------------------------------|--------------|
31
+ | Rails 4.1 | MRI 1.9.3, 2.0.0, 2.1.2, 2.2.0 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-4.1)](https://travis-ci.org/jhund/filterrific_demo)|
32
+ | Rails 4.0 | MRI 1.9.3, 2.0.0, 2.1.2, 2.2.0 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-4.0)](https://travis-ci.org/jhund/filterrific_demo)|
33
+ | Rails 3.2 | MRI 1.9.3, 2.0.0, 2.1.2 | mysql, mysql2, postgresql, sqlite3 |[![Build Status](https://travis-ci.org/jhund/filterrific_demo.svg?branch=rails-3.2)](https://travis-ci.org/jhund/filterrific_demo)|
36
34
 
37
35
  Filterrific version 1.4.0 should work on older versions of Rails and Ruby, however
38
36
  the 1.x branch is not supported any more.
@@ -65,6 +63,12 @@ I'm happy to help you if you encounter problems when using filterrific. You'll m
65
63
 
66
64
  [![Code Climate](https://codeclimate.com/github/jhund/filterrific.png)](https://codeclimate.com/github/jhund/filterrific)
67
65
 
66
+ ### Related projects
67
+
68
+ * has_scope
69
+ * http://www.justinweiss.com/blog/2014/02/17/search-and-filter-rails-models-without-bloating-your-controller/
70
+ * https://github.com/laserlemon/periscope
71
+
68
72
  ### License
69
73
 
70
74
  [MIT licensed](https://github.com/jhund/filterrific/blob/master/MIT-LICENSE).
data/lib/filterrific.rb CHANGED
@@ -1,11 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'filterrific/version'
2
4
  require 'filterrific/engine'
3
5
 
4
6
  module Filterrific
5
-
6
- # Wrapper around Filterrific::ParamSet initialization
7
- def self.new(a_resource_class, filterrific_params = {})
8
- Filterrific::ParamSet.new(a_resource_class, filterrific_params)
9
- end
10
-
11
7
  end
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Adds Filterrific methods ActionController instances
4
+ #
5
+ module Filterrific
6
+ module ActionControllerExtension
7
+
8
+ protected
9
+
10
+ # @param model_class [Class]
11
+ # @param filterrific_params [Hash] typically the Rails request params under
12
+ # the :filterrific key (params[:filterrific]), however can be any Hash.
13
+ # @param opts [Hash]
14
+ # @option opts [Array<String>, optional] :available_filters
15
+ # further restrict which of the filters specified in the model are
16
+ # available in this context.
17
+ # @option opts [Hash, optional] :default_filter_params
18
+ # overrides the defaults specified in the model.
19
+ # @option opts [String, Symbol, optional] :persistence_id
20
+ # defaults to "namespace/controller#action" string, used for session key
21
+ # and saved searches to isolate different filters' persisted params from
22
+ # each other.
23
+ # @option opts [Hash, optional] :select_options
24
+ # these are available in the view to populate select lists and other
25
+ # dynamic values.
26
+ # @return [Filterrific::ParamSet]
27
+ def initialize_filterrific(model_class, filterrific_params, opts)
28
+ f_params = (filterrific_params || {}).deep_stringify_keys
29
+ opts = opts.stringify_keys
30
+ pi = opts['persistence_id'] || compute_default_persistence_id
31
+
32
+ if (f_params.delete('reset_filterrific'))
33
+ # Reset query and session_persisted params
34
+ session[pi] = nil
35
+ redirect_to url_for({}) and return false # works with `or return` in calling action.
36
+ end
37
+
38
+ f_params = f_params.presence || # start with passed in params
39
+ session[pi].presence || # then try session persisted params
40
+ opts['default_filter_params'] || # then use passed in opts
41
+ model_class.filterrific_default_filter_params # finally use model_class defaults
42
+
43
+ f_params.deep_stringify_keys!
44
+ f_params.slice!(opts['available_filters'].map(&:to_s)) if opts['available_filters']
45
+
46
+ filterrific = Filterrific::ParamSet.new(model_class, f_params)
47
+ filterrific.select_options = opts['select_options']
48
+ session[pi] = filterrific.to_hash
49
+ filterrific
50
+ end
51
+
52
+ # Computes a default persistence id based on controller and action name
53
+ def compute_default_persistence_id
54
+ [controller_name, action_name].join('#')
55
+ end
56
+
57
+ end
58
+ end
@@ -1,23 +1,25 @@
1
1
  # -*- coding: utf-8 -*-
2
-
3
2
  #
4
- # Adds view helpers to ActionView
3
+ # Adds Filterrific view helpers to ActionView instances
5
4
  #
6
5
  module Filterrific
7
6
  module ActionViewExtension
8
7
 
9
- # Sets all options on form_for to defaults if called with Filterrific object
10
- def form_for(record, options = {}, &block)
11
- if record.is_a?(Filterrific::ParamSet)
12
- options[:as] ||= :filterrific
13
- options[:html] ||= {}
14
- options[:html][:method] ||= :get
15
- options[:html][:id] ||= :filterrific_filter
16
- options[:url] ||= url_for(:controller => controller.controller_name, :action => controller.action_name)
17
- end
18
- super
8
+ # Sets all options on form_for to defaults that work with Filterrific
9
+ # @param record [Filterrific] the @filterrific object
10
+ # @param options [Hash] standard options for form_for
11
+ # @param block [Proc] the form body
12
+ def form_for_filterrific(record, options = {}, &block)
13
+ options[:as] ||= :filterrific
14
+ options[:html] ||= {}
15
+ options[:html][:method] ||= :get
16
+ options[:html][:id] ||= :filterrific_filter
17
+ options[:url] ||= url_for(
18
+ :controller => controller.controller_name,
19
+ :action => controller.action_name
20
+ )
21
+ form_for(record, options, &block)
19
22
  end
20
- # TODO: change this to form_for_filterrific!
21
23
 
22
24
  # Renders a spinner while the list is being updated
23
25
  def render_filterrific_spinner
@@ -27,36 +29,40 @@ module Filterrific
27
29
  </span>
28
30
  ).html_safe
29
31
  end
30
- #alias: filterrific_spinner
31
32
 
32
33
  # Renders a link which indicates the current sorting and which can be used to
33
34
  # toggle the list sorting (set column and direction).
35
+ #
34
36
  # NOTE: Make sure that this is used in the list partial that is re-rendered
35
37
  # when the filterrific params are changed, so that the filterrific params in
36
38
  # the URL are always current.
37
- # @param[Filterrific::ParamSet] filterrific the current filterrific instance
38
- # @param[String, Symbol] sort_key the key to sort by, without direction.
39
+ #
40
+ # NOTE: Currently the filterrific_sorting_link is not synchronized with a
41
+ # SELECT input you may have in the filter form for sorting. We recommend you
42
+ # use one or the other to avoid conflicting sort settings in the UI.
43
+ #
44
+ # @param filterrific [Filterrific::ParamSet] the current filterrific instance
45
+ # @param sort_key [String, Symbol] the key to sort by, without direction.
39
46
  # Example: 'name', 'created_at'
40
- # @param[Hash, optional] options:
41
- # * active_column_class: CSS class applied to current sort column.
42
- # Default: 'filterrific_current_sort_column'
43
- # * ascending_indicator: HTML string to indicate ascending sort direction.
44
- # Default: Triangle pointing up.
45
- # * default_sort_direction: override the default sorting when selecting
46
- # a new sort column. Default: 'asc'.
47
- # * descending_indicator: HTML string to indicate descending sort direction.
48
- # Default: Triangle pointing down.
49
- # * html_attrs: HTML attributes to be added to the sorting link. Default: {}
50
- # * label: override label. Default: `sort_key.humanize`.
51
- # * sorting_scope_name: override the name of the scope used for sorting.
52
- # Default: `:sorted_by`
53
- # * url_for_attrs: override the target URL attributes to be used for `url_for`.
54
- # Default: {} (current URL).
55
- # TODO: update documentation
56
- # TODO: update demo app
57
- # TODO: synchronize with sorting select in filter
58
- def filterrific_sorting_link(filterrific, sort_key, options = {})
59
- options = {
47
+ # @param opts [Hash, optional]
48
+ # @options opts [String, optional] active_column_class
49
+ # CSS class applied to current sort column. Default: 'filterrific_current_sort_column'
50
+ # @options opts [String, optional] ascending_indicator
51
+ # HTML string to indicate ascending sort direction. Default: '⬆'
52
+ # @options opts [String, optional] default_sort_direction
53
+ # Override the default sorting when selecting a new sort column. Default: 'asc'.
54
+ # @options opts [String, optional] descending_indicator
55
+ # HTML string to indicate descending sort direction. Default: '⬇'
56
+ # @options opts [Hash, optional] html_attrs
57
+ # HTML attributes to be added to the sorting link. Default: {}
58
+ # @options opts [String, optional] label
59
+ # Override label. Default: `sort_key.to_s.humanize`.
60
+ # @options opts [String, Symbol, optional] sorting_scope_name
61
+ # Override the name of the scope used for sorting. Default: :sorted_by
62
+ # @options opts [Hash, optional] url_for_attrs
63
+ # Override the target URL attributes to be used for `url_for`. Default: {} (current URL).
64
+ def filterrific_sorting_link(filterrific, sort_key, opts = {})
65
+ opts = {
60
66
  :active_column_class => 'filterrific_current_sort_column',
61
67
  :inactive_column_class => 'filterrific_sort_column',
62
68
  :ascending_indicator => '⬆',
@@ -66,52 +72,82 @@ module Filterrific
66
72
  :label => sort_key.to_s.humanize,
67
73
  :sorting_scope_name => :sorted_by,
68
74
  :url_for_attrs => {},
69
- }.merge(options)
70
- options[:html_attrs] = options[:html_attrs].with_indifferent_access
71
- current_sorting = filterrific.send(options[:sorting_scope_name])
72
- current_sort_key = current_sorting ? current_sorting.gsub(/_asc|_desc/, '') : nil
73
- current_sort_direction = current_sorting ? (current_sorting =~ /_desc\z/ ? 'desc' : 'asc') : nil
75
+ }.merge(opts)
76
+ opts.merge!(
77
+ :html_attrs => opts[:html_attrs].with_indifferent_access,
78
+ :current_sorting => filterrific.send(opts[:sorting_scope_name]),
79
+ :current_sort_key => current_sorting ? current_sorting.gsub(/_asc|_desc/, '') : nil,
80
+ :current_sort_direction => current_sorting ? (current_sorting =~ /_desc\z/ ? 'desc' : 'asc') : nil,
81
+ )
74
82
  new_sort_key = sort_key.to_s
75
- if new_sort_key == current_sort_key
76
- # current sort column, toggle search_direction
77
- new_sort_direction, current_sort_direction_indicator = if 'asc' == current_sort_direction
78
- ['desc', options[:ascending_indicator]]
79
- else
80
- ['asc', options[:descending_indicator]]
81
- end
82
- new_sorting = [new_sort_key, new_sort_direction].join('_')
83
- css_classes = [
84
- options[:active_column_class],
85
- options[:html_attrs].delete(:class)
86
- ].compact.join(' ')
87
- new_filterrific_params = filterrific.to_hash
88
- .with_indifferent_access
89
- .merge(options[:sorting_scope_name] => new_sorting)
90
- url_for_attrs = options[:url_for_attrs].merge(:filterrific => new_filterrific_params)
91
- link_to(
92
- [options[:label], current_sort_direction_indicator].join(' '),
93
- url_for(url_for_attrs),
94
- options[:html_attrs].reverse_merge(:class => css_classes, :method => :get, :remote => true)
95
- )
83
+ if new_sort_key == opts[:current_sort_key]
84
+ # same sort column, reverse order
85
+ filterrific_sorting_link_reverse_order(filterrific, new_sort_key, opts)
96
86
  else
97
- # new sort column, change sort column
98
- new_sort_direction = options[:default_sort_direction]
99
- new_sorting = [new_sort_key, new_sort_direction].join('_')
100
- css_classes = [
101
- options[:inactive_column_class],
102
- options[:html_attrs].delete(:class)
103
- ].compact.join(' ')
104
- new_filterrific_params = filterrific.to_hash
105
- .with_indifferent_access
106
- .merge(options[:sorting_scope_name] => new_sorting)
107
- url_for_attrs = options[:url_for_attrs].merge(:filterrific => new_filterrific_params)
108
- link_to(
109
- options[:label],
110
- url_for(url_for_attrs),
111
- options[:html_attrs].reverse_merge(:class => css_classes, :method => :get, :remote => true)
112
- )
87
+ # new sort column, default sort order
88
+ filterrific_sorting_link_new_column(filterrific, new_sort_key, opts)
113
89
  end
114
90
  end
115
91
 
92
+ # Returns a url that can be used to reset the Filterrific params
93
+ def reset_filterrific_url(opts = {})
94
+ url_for(
95
+ { filterrific: { reset_filterrific: true } }.merge(opts)
96
+ )
97
+ end
98
+
99
+ protected
100
+
101
+ # Renders HTML to reverse sort order on currently sorted column.
102
+ # @param filterrific [Filterrific::ParamSet]
103
+ # @param new_sort_key [String]
104
+ # @param opts [Hash]
105
+ # @return [String] an HTML fragment
106
+ def filterrific_sorting_link_reverse_order(filterrific, new_sort_key, opts)
107
+ # current sort column, toggle search_direction
108
+ new_sort_direction, current_sort_direction_indicator = if 'asc' == opts[:current_sort_direction]
109
+ ['desc', opts[:ascending_indicator]]
110
+ else
111
+ ['asc', opts[:descending_indicator]]
112
+ end
113
+ new_sorting = [new_sort_key, new_sort_direction].join('_')
114
+ css_classes = [
115
+ opts[:active_column_class],
116
+ opts[:html_attrs].delete(:class)
117
+ ].compact.join(' ')
118
+ new_filterrific_params = filterrific.to_hash
119
+ .with_indifferent_access
120
+ .merge(opts[:sorting_scope_name] => new_sorting)
121
+ url_for_attrs = opts[:url_for_attrs].merge(:filterrific => new_filterrific_params)
122
+ link_to(
123
+ [opts[:label], opts[:current_sort_direction_indicator]].join(' '),
124
+ url_for(url_for_attrs),
125
+ opts[:html_attrs].reverse_merge(:class => css_classes, :method => :get, :remote => true)
126
+ )
127
+ end
128
+
129
+ # Renders HTML to sort by a new column.
130
+ # @param filterrific [Filterrific::ParamSet]
131
+ # @param new_sort_key [String]
132
+ # @param opts [Hash]
133
+ # @return [String] an HTML fragment
134
+ def filterrific_sorting_link_new_column(filterrific, new_sort_key, opts)
135
+ new_sort_direction = opts[:default_sort_direction]
136
+ new_sorting = [new_sort_key, new_sort_direction].join('_')
137
+ css_classes = [
138
+ opts[:inactive_column_class],
139
+ opts[:html_attrs].delete(:class)
140
+ ].compact.join(' ')
141
+ new_filterrific_params = filterrific.to_hash
142
+ .with_indifferent_access
143
+ .merge(opts[:sorting_scope_name] => new_sorting)
144
+ url_for_attrs = opts[:url_for_attrs].merge(:filterrific => new_filterrific_params)
145
+ link_to(
146
+ opts[:label],
147
+ url_for(url_for_attrs),
148
+ opts[:html_attrs].reverse_merge(:class => css_classes, :method => :get, :remote => true)
149
+ )
150
+ end
151
+
116
152
  end
117
153
  end
@@ -1,51 +1,58 @@
1
+ # -*- coding: utf-8 -*-
1
2
  #
2
- # Adds filterrific methods to ActiveRecord::Base and sub classes.
3
+ # Adds Filterrific methods to ActiveRecord::Base model_class.
3
4
  #
4
5
  require 'filterrific/param_set'
5
6
 
6
7
  module Filterrific
7
8
  module ActiveRecordExtension
8
9
 
9
- # Adds filterrific behavior to class when called like so:
10
+ # Adds Filterrific behavior to class when called like so:
10
11
  #
11
12
  # filterrific(
12
- # :default_settings => { :sorted_by => "created_at_asc" },
13
- # :filter_names => [:sorted_by, :search_query, :with_state]
13
+ # :available_filters => [:sorted_by, :search_query, :with_state]
14
+ # :default_filter_params => { :sorted_by => "created_at_asc" },
14
15
  # )
15
16
  #
16
- # @params[Hash] options
17
- # Required keys are:
18
- # * :filter_names: a list of filter_names to be exposed by Filterrific
19
- # Optional keys are:
20
- # * :default_settings: default filter settings
21
- def filterrific(options)
22
- cattr_accessor :filterrific_default_settings
23
- cattr_accessor :filterrific_filter_names
24
-
25
- options.stringify_keys!
26
-
27
- assign_filterrific_filter_names(options)
28
- validate_filterrific_filter_names
29
- assign_filterrific_default_settings(options)
30
- validate_filterrific_default_settings
17
+ # @params opts [Hash] with either string or symbol keys, will be stringified.
18
+ # @option opts [Array<String, Symbol>] available_filters: a list of filters to be exposed by Filterrific.
19
+ # @option opts [Hash, optional] default_filter_params: default filter parameters
20
+ # @return [void]
21
+ def filterrific(opts)
22
+ cattr_accessor :filterrific_available_filters
23
+ cattr_accessor :filterrific_default_filter_params
24
+ self.filterrific_available_filters = []
25
+
26
+ opts.stringify_keys!
27
+
28
+ define_sorted_by_scope(opts['sorted_by']) if opts['sorted_by']
29
+ #define_search_query_scope(opts['search_query']) if opts['search_query']
30
+
31
+ assign_filterrific_available_filters(opts)
32
+ validate_filterrific_available_filters
33
+ assign_filterrific_default_filter_params(opts)
34
+ validate_filterrific_default_filter_params
35
+
31
36
  end
32
37
 
33
- # Returns ActiveRecord relation based on given filterrific_param_set.
34
- # Use like so:
35
- # ModelClass.filterrific_find(@filterrific_param_set)
38
+ # Returns ActiveRecord relation based on filterrific_param_set.
39
+ # Use like so: `ModelClass.filterrific_find(@filterrific)`
36
40
  #
37
- # @param[Filterrific::ParamSet] filterrific_param_set
38
- # @return[ActiveRecord::Relation] an ActiveRecord relation.
41
+ # @param filterrific_param_set [Filterrific::ParamSet]
42
+ # @return [ActiveRecord::Relation] with filters applied
39
43
  def filterrific_find(filterrific_param_set)
40
44
  unless filterrific_param_set.is_a?(Filterrific::ParamSet)
41
- raise(ArgumentError, "Invalid Filterrific::ParamSet: #{ filterrific_param_set.inspect }")
45
+ raise(
46
+ ArgumentError,
47
+ "Invalid Filterrific::ParamSet: #{ filterrific_param_set.inspect }"
48
+ )
42
49
  end
43
50
 
44
- # initialize active record relation
45
- ar_rel = if ::ActiveRecord::Relation === self
51
+ # Initialize ActiveRecord::Relation
52
+ ar_rel = if ActiveRecord::Relation === self
46
53
  # self is already an ActiveRecord::Relation, use as is
47
54
  self
48
- elsif 3 >= Rails::VERSION::MAJOR
55
+ elsif Rails::VERSION::MAJOR <= 3
49
56
  # Active Record 3: send `:scoped` to class to get an ActiveRecord::Relation
50
57
  scoped
51
58
  else
@@ -53,8 +60,8 @@ module Filterrific
53
60
  all
54
61
  end
55
62
 
56
- # apply filterrific params
57
- self.filterrific_filter_names.each do |filter_name|
63
+ # Apply filterrific params
64
+ filterrific_available_filters.each do |filter_name|
58
65
  filter_param = filterrific_param_set.send(filter_name)
59
66
  next if filter_param.blank? # skip blank filter_params
60
67
  ar_rel = ar_rel.send(filter_name, filter_param)
@@ -65,29 +72,42 @@ module Filterrific
65
72
 
66
73
  protected
67
74
 
68
- def assign_filterrific_filter_names(options)
69
- self.filterrific_filter_names = (
70
- options['filter_names'] || options['scope_names'] || []
71
- ).map { |e| e.to_s }
75
+ # Defines a :sorted_by scope based on attrs
76
+ # @param attrs [Hash] with keys as
77
+ def define_sorted_by_scope(attrs)
78
+ scope :sorted_by, lambda {}
72
79
  end
73
80
 
74
- def validate_filterrific_filter_names
75
- # Raise exception if not filter_names are given
76
- raise(ArgumentError, ":filter_names can't be empty") if filterrific_filter_names.blank?
81
+ # Assigns available filters.
82
+ # @param opts [Hash] the complete options hash passed to `filterrific`.
83
+ # This method uses the 'available_filters', 'sorted_by', and 'search_query' keys.
84
+ # @return [void]
85
+ def assign_filterrific_available_filters(opts)
86
+ self.filterrific_available_filters = (
87
+ filterrific_available_filters + (opts['available_filters'] || [])
88
+ ).map(&:to_s).uniq.sort
89
+ end
90
+
91
+ # Validates presence of at least one available filter.
92
+ # @return [void]
93
+ def validate_filterrific_available_filters
94
+ if filterrific_available_filters.blank?
95
+ raise(ArgumentError, ":available_filters can't be empty")
96
+ end
77
97
  end
78
98
 
79
- def assign_filterrific_default_settings(options)
80
- self.filterrific_default_settings = (
81
- options['default_settings'] || options['defaults'] || {}
99
+ def assign_filterrific_default_filter_params(opts)
100
+ self.filterrific_default_filter_params = (
101
+ opts['default_filter_params'] || {}
82
102
  ).stringify_keys
83
103
  end
84
104
 
85
- def validate_filterrific_default_settings
86
- # Raise exception if defaults contain keys that are not present in filter_names
105
+ def validate_filterrific_default_filter_params
106
+ # Raise exception if defaults contain keys that are not present in available_filters
87
107
  if (
88
- invalid_defaults = (filterrific_default_settings.keys - filterrific_filter_names)
108
+ inv_fdfps = filterrific_default_filter_params.keys - filterrific_available_filters
89
109
  ).any?
90
- raise(ArgumentError, "Invalid default keys: #{ invalid_defaults.inspect }")
110
+ raise(ArgumentError, "Invalid default filter params: #{ inv_fdfps.inspect }")
91
111
  end
92
112
  end
93
113
 
@@ -1,4 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'filterrific/param_set'
4
+
5
+ require 'filterrific/action_controller_extension'
2
6
  require 'filterrific/action_view_extension'
3
7
  require 'filterrific/active_record_extension'
4
8
 
@@ -10,14 +14,18 @@ module Filterrific
10
14
 
11
15
  isolate_namespace Filterrific
12
16
 
13
- ActiveSupport.on_load :active_record do
14
- extend Filterrific::ActiveRecordExtension
17
+ ActiveSupport.on_load :action_controller do
18
+ include Filterrific::ActionControllerExtension
15
19
  end
16
20
 
17
21
  ActiveSupport.on_load :action_view do
18
22
  include Filterrific::ActionViewExtension
19
23
  end
20
24
 
25
+ ActiveSupport.on_load :active_record do
26
+ extend Filterrific::ActiveRecordExtension
27
+ end
28
+
21
29
  initializer "filterrific" do |app|
22
30
  app.config.assets.precompile += %w(filterrific-spinner.gif)
23
31
  end
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'active_support/all'
2
4
  require 'digest/sha1'
3
5
 
@@ -6,35 +8,44 @@ module Filterrific
6
8
  # FilterParamSet is a container to store FilterParams
7
9
  class ParamSet
8
10
 
9
- attr_accessor :resource_class
11
+ attr_accessor :model_class
10
12
  attr_accessor :select_options
11
13
 
12
- def initialize(a_resource_class, filterrific_params = {})
13
- self.resource_class = a_resource_class
14
+ # Initializes a new Filterrific::ParamSet. This is the core of Filterrific
15
+ # where all the action happens.
16
+ # @param a_model_class [Class] the class you want to filter records of
17
+ # @param filterrific_params [Hash, optional] the filter params, uses
18
+ # model_class' default_settings
19
+ # @return [Filterrific::ParamSet]
20
+ def initialize(a_model_class, filterrific_params = {})
21
+ self.model_class = a_model_class
14
22
  @select_options = {}
15
23
 
16
24
  # Use either passed in filterrific_params or resource class' default_settings.
17
25
  # Don't merge the hashes. This causes trouble if an option is set to nil
18
26
  # by the user, then it will be overriden by default_settings.
19
27
  # You might wonder "what if I want to change only one thing from the defaults?"
20
- # Persistence, baby. By the time you submit changes to one dimension, all the others
28
+ # Persistence, baby. By the time you submit changes to one filter, all the others
21
29
  # will be already initialized with the defaults.
22
- filterrific_params = resource_class.filterrific_default_settings if filterrific_params.blank?
30
+ filterrific_params = model_class.filterrific_default_settings if filterrific_params.blank?
23
31
  filterrific_params.stringify_keys!
24
32
  filterrific_params = condition_filterrific_params(filterrific_params)
25
- define_attr_accessors_for_each_filter(filterrific_params)
33
+ define_and_assign_attr_accessors_for_each_filter(filterrific_params)
26
34
  end
27
35
 
28
- # A shortcut to run the ActiveRecord query on resource_class. Use this if
29
- # you want to start with the resource_class, and not a special ActiveRecord::Relation.
36
+ # A shortcut to run the ActiveRecord query on model_class. Use this if
37
+ # you want to start with the model_class, and not an existing ActiveRecord::Relation.
38
+ # Allows `@filterrific.find` in controller instead of
39
+ # `ModelClass.filterrific_find(@filterrific)`
30
40
  def find
31
- resource_class.filterrific_find(self)
41
+ model_class.filterrific_find(self)
32
42
  end
33
43
 
34
44
  # Returns Filterrific::ParamSet as hash (used for URL params and serialization)
45
+ # @return [Hash] with stringified keys
35
46
  def to_hash
36
47
  {}.tap { |h|
37
- resource_class.filterrific_filter_names.each do |filter_name|
48
+ model_class.filterrific_available_filters.each do |filter_name|
38
49
  param_value = self.send(filter_name)
39
50
  case
40
51
  when param_value.blank?
@@ -49,27 +60,16 @@ module Filterrific
49
60
  }
50
61
  end
51
62
 
63
+ # Returns params as JSON string.
64
+ # @return [String]
52
65
  def to_json
53
66
  to_hash.to_json
54
67
  end
55
68
 
56
- # Returns a signature that is unique to self's params
57
- def signature
58
- Digest::SHA1.hexdigest(to_hash.to_a.sort.to_s)
59
- end
60
-
61
- # Returns true if this Filterrific::ParamSet is not the model's default.
62
- # TODO: this doesn't work for procs. I need to evaluate the
63
- # filterrific_default_settings before comparing them to to_hash.
64
- #
65
- # def customized?
66
- # resource_class.filterrific_default_settings != to_hash
67
- # end
68
-
69
69
  protected
70
70
 
71
- # Conditions params
72
- # @param[Hash] fp the filterrific params hash
71
+ # Conditions params: Evaluates Procs and type casts integer values.
72
+ # @param fp [Hash] the filterrific params hash
73
73
  # @return[Hash] the conditioned params hash
74
74
  def condition_filterrific_params(fp)
75
75
  fp.each do |key, val|
@@ -88,11 +88,11 @@ module Filterrific
88
88
  fp
89
89
  end
90
90
 
91
- # Defines attr accessors for each filter name on self and assigns
92
- # values based on fp
93
- # @param[Hash] fp filterrific_params
94
- def define_attr_accessors_for_each_filter(fp)
95
- resource_class.filterrific_filter_names.each do |filter_name|
91
+ # Defines attr accessors for each available_filter on self and assigns
92
+ # values based on fp.
93
+ # @param fp [Hash] filterrific_params with stringified keys
94
+ def define_and_assign_attr_accessors_for_each_filter(fp)
95
+ model_class.filterrific_available_filters.each do |filter_name|
96
96
  self.class.send(:attr_accessor, filter_name)
97
97
  v = fp[filter_name]
98
98
  self.send("#{ filter_name }=", v) if v.present?
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  module Filterrific
2
- VERSION = "1.4.3"
4
+ VERSION = "2.0.0"
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filterrific
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jo Hund
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-13 00:00:00.000000000 Z
11
+ date: 2015-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - '>='
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.7.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.7.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -70,14 +70,14 @@ dependencies:
70
70
  name: wwtd
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.5.5
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.5.5
83
83
  description: Filterrific is a Rails Engine plugin that makes it easy to filter, search,
@@ -101,9 +101,9 @@ files:
101
101
  - doc/development_notes/model_api.rb
102
102
  - doc/development_notes/view_api.txt
103
103
  - doc/meta.md
104
- - doc/rails_conf_talk.md
105
104
  - doc/scratchpad.md
106
105
  - lib/filterrific.rb
106
+ - lib/filterrific/action_controller_extension.rb
107
107
  - lib/filterrific/action_view_extension.rb
108
108
  - lib/filterrific/active_record_extension.rb
109
109
  - lib/filterrific/engine.rb
@@ -126,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - '>='
128
128
  - !ruby/object:Gem::Version
129
- version: '0'
129
+ version: 1.9.3
130
130
  required_rubygems_version: !ruby/object:Gem::Requirement
131
131
  requirements:
132
132
  - - '>='
@@ -1,33 +0,0 @@
1
- # Filterrific Rails Conf Talk
2
-
3
-
4
- Topics to cover:
5
-
6
- * filter and sort ActiveRecord lists end to end with lots of code
7
- * AR scope patterns
8
- * advanced use cases
9
- * export to CSV/XLS
10
- * saved searches
11
- * full text search
12
- * multiple form inputs for single scope
13
- * checkbox arrays (collection_check_boxes)
14
- * filter persistence strategies
15
- * session
16
- * none (query param)
17
- * database (saved searches)
18
-
19
- Target audience:
20
-
21
- * intermediate
22
-
23
-
24
- Title ideas:
25
-
26
- * Tame/awesomify your ActiveRecord lists with Filterrific
27
- * Dive deep into ActiveRecord scopes, and learn about Filterrific
28
- * Slice and dice your data in many ways with AR scopes and Filterrific
29
-
30
- Other talk ideas (possibly lightning talks?):
31
-
32
- * How to safely mutate objects in Rails
33
- * Service objects, DCI, processors: all dependencies go in one direction