filterrific 0.2.0 → 1.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.
- data/CHANGELOG.md +5 -0
- data/LICENSE +1 -1
- data/VERSION +1 -1
- data/doc/development_notes/api_design.txt +140 -0
- data/doc/development_notes/controller_api.txt +27 -0
- data/doc/development_notes/model_api.rb +485 -0
- data/doc/development_notes/view_api.txt +49 -0
- data/doc/documentation.md +4 -2
- data/doc/ideas.txt +40 -44
- data/doc/todo.md +14 -1
- data/filterrific.gemspec +31 -34
- data/lib/filterrific/model_mixin.rb +6 -6
- metadata +22 -11
- data/.gitignore +0 -17
data/CHANGELOG.md
CHANGED
data/LICENSE
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
@@ -0,0 +1,140 @@
|
|
1
|
+
Conventions and API for filterrific scopes:
|
2
|
+
|
3
|
+
Philosophy:
|
4
|
+
|
5
|
+
auto generate simple scopes. Any customization is done by overriding the scope. Give
|
6
|
+
lots of examples and annotated code.
|
7
|
+
|
8
|
+
List of exposed scopes. On first request, load and cache them so that all meta-code has had a chance
|
9
|
+
to run (e.g. to dynamically generate scopes).
|
10
|
+
|
11
|
+
Only filters defined in filterrific will be exposed via URL. Other scopes will not be accessible
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
CONFIG
|
16
|
+
===============================================================================
|
17
|
+
|
18
|
+
* persist_in_session
|
19
|
+
* default_label_method (for view helper selects, radio buttons, checkboxes), default => :name
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Examples
|
26
|
+
|
27
|
+
|
28
|
+
CVIMS:
|
29
|
+
* with_publishing_status: custom, looks at state as well as date
|
30
|
+
* search_query
|
31
|
+
* sorted_by: extracts direction, applies lower(...) to string columns
|
32
|
+
* with_tags IN
|
33
|
+
* authored_by belongs_to, { :author_id => [*author_ids] }
|
34
|
+
|
35
|
+
|
36
|
+
PTS:
|
37
|
+
* has_list_options :defaults => {
|
38
|
+
:publication_date_min => lambda { Date.new(Date.today.year, 1, 1).to_s(:calendar_display_area) },
|
39
|
+
:publication_date_max => lambda { Date.new(Date.today.year + 3, 12, 31).to_s(:calendar_display_area) },
|
40
|
+
:sorted_by => 'publication_date_asc',
|
41
|
+
:with_language => Language.all.map(&:id),
|
42
|
+
:with_programme => Programme.all.map(&:id),
|
43
|
+
:with_publication_status => [1, 2, 5, 7],
|
44
|
+
:with_publication_type => PublicationType.all.map(&:id) - [PublicationType.find_partner.nil_or(:id)],
|
45
|
+
:with_sales_item_status => %w[sales_item non_sales_item],
|
46
|
+
:with_commercial_title_status => %w[commercial_title non_commercial_title]
|
47
|
+
}
|
48
|
+
* interesting method: condition_publication_date_for_named_scope (allows pseudo procs for dates).
|
49
|
+
helpful because procs cannot be marshalled
|
50
|
+
* # have to use :include instead of :joins for :roles. If I use :joins, it does an inner join and
|
51
|
+
# returns duplicates for publications. Same for :with_role_type scope.
|
52
|
+
# roles is a habtm relation with publication.
|
53
|
+
named_scope :with_person, lambda{ |person_ids|
|
54
|
+
{
|
55
|
+
:conditions => ["roles.person_id IN (?)", [*person_ids].map(&:to_i)],
|
56
|
+
:include => :roles
|
57
|
+
}
|
58
|
+
}
|
59
|
+
* named_scope :with_commercial_title_status, lambda{ |statuses|
|
60
|
+
v = ['1 = 2'] # never true, used if no checkbox is checked ("0")
|
61
|
+
v << 'publications.service_category_id = 1' if statuses.include?("commercial_title")
|
62
|
+
v << 'publications.service_category_id != 1' if statuses.include?("non_commercial_title")
|
63
|
+
{ :conditions => v.join(' OR ') }
|
64
|
+
}
|
65
|
+
* named_scope :sorted_by, lambda { |sort_option|
|
66
|
+
# every sorting should have a set of secondary sort keys. We append those for each case where applicable.
|
67
|
+
secondary_sort_keys = "publications.publication_date asc, lower(publications.short_title) asc, publications.id asc"
|
68
|
+
direction = (sort_option =~ /desc$/) ? 'desc' : 'asc'
|
69
|
+
case sort_option.to_s
|
70
|
+
when /^extent_/
|
71
|
+
{ :order => "publications.extent #{direction}" }
|
72
|
+
when /^language_/
|
73
|
+
{ :order => "lower(languages.name) #{direction}, #{secondary_sort_keys}",
|
74
|
+
:joins => :language }
|
75
|
+
when /^PM_/
|
76
|
+
{ :order => "lower(publications.project_manager_name) #{direction}, #{secondary_sort_keys}" }
|
77
|
+
when /^programme_/
|
78
|
+
{ :order => "lower(programmes.name) #{direction}, #{secondary_sort_keys}",
|
79
|
+
:joins => :programme }
|
80
|
+
else
|
81
|
+
raise(ArgumentError, "Invalid sort option: #{sort_option.inspect}")
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
TIRO
|
88
|
+
* filterrific :defaults => {
|
89
|
+
:sorted_by => 'most_recent',
|
90
|
+
:on_or_after => lambda { Time.zone.now.beginning_of_month.to_s(:date) },
|
91
|
+
:billable => true
|
92
|
+
}
|
93
|
+
* scope :billable, lambda{ |yes_or_no|
|
94
|
+
case yes_or_no
|
95
|
+
when "yes", true
|
96
|
+
where('activities.is_billable = ?', true)
|
97
|
+
when "no", false
|
98
|
+
where('activities.is_billable = ?', false)
|
99
|
+
else
|
100
|
+
# no setting, don't return any conditions
|
101
|
+
end
|
102
|
+
}
|
103
|
+
* scope :for_person, lambda { |person| where("projects.person_id = ?", person.id).joins(:project) }
|
104
|
+
* scope :for_date_range, lambda{ |dates|
|
105
|
+
where('activities.date <= ? AND activities.date >= ?', dates.max, dates.min)
|
106
|
+
}
|
107
|
+
* scope :on_or_after, lambda{ |date|
|
108
|
+
d = Date.parse(date) if date.is_a?(String)
|
109
|
+
where('activities.date >= ? ', d)
|
110
|
+
}
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
CANDO
|
116
|
+
* saved searches
|
117
|
+
* named_scope :search_query, lambda{ |query|
|
118
|
+
# Matches using LIKE. LIKE is case INsensitive with MySQL (Development),
|
119
|
+
# however it is case sensitive with PostGreSQL (Heroku)
|
120
|
+
# To make it work in both worlds, I force everything to lower case.
|
121
|
+
return {} unless query.is_a?(String)
|
122
|
+
# condition query string, parse into individual keywords
|
123
|
+
terms = query.downcase.split(/\s+/)
|
124
|
+
# replace "*" with "%" for wildcard searches
|
125
|
+
terms = terms.map { |e| e.gsub('*', '%') }
|
126
|
+
{
|
127
|
+
:conditions => [
|
128
|
+
terms.map { |term|
|
129
|
+
"lower(conference_participations._first_name) LIKE ? OR lower(conference_participations._last_name) LIKE ?"
|
130
|
+
}.join(' AND '),
|
131
|
+
*(terms.map { |e| e.downcase } * 2)
|
132
|
+
]
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
STRATADOCS
|
139
|
+
|
140
|
+
* list starts with self as AR proxy
|
@@ -0,0 +1,27 @@
|
|
1
|
+
CONTROLLER
|
2
|
+
==========
|
3
|
+
|
4
|
+
There are two methods you use in a controller:
|
5
|
+
* filterrific_init to initialize the Filterrific object. It is stored in the @filterrific ivar. This
|
6
|
+
method first initializes the filter params:
|
7
|
+
params[param_name] || session[session_key] || Model.filterrific_defaults
|
8
|
+
Then it persists the filter_params in the session, using session_key.
|
9
|
+
* Model.filterrific_find to populate your ActiveRecord collection based on filterrific params.
|
10
|
+
filterrific_find is a composable ActiveRecord relation. That means you can chain it with other
|
11
|
+
relations like scopes, pagination, etc.
|
12
|
+
|
13
|
+
Example controller code:
|
14
|
+
|
15
|
+
def index
|
16
|
+
@filterrific = filterrific_init(Publication, options={})
|
17
|
+
Options:
|
18
|
+
* :persist_in_session => true OR "publications_list" # if true, builds session_key from
|
19
|
+
controller-action
|
20
|
+
* :debug => false # if true, prints out debug info. This also exists in view helper. Maybe one to
|
21
|
+
logger/STDOUT, the other to view?
|
22
|
+
* :param_prefix => "filterrific" # the param prefix used to shuttle params between view and controller.
|
23
|
+
|
24
|
+
@publications = Publication.filterrific_find(@filterrific).paginate....
|
25
|
+
@publications = current_user.publications.filterrific_find(@filterrific).paginate....
|
26
|
+
...
|
27
|
+
end
|
@@ -0,0 +1,485 @@
|
|
1
|
+
filterrific do
|
2
|
+
filter :with_project
|
3
|
+
sort ...
|
4
|
+
search ...
|
5
|
+
config :prefix, 'lala'
|
6
|
+
config.debug = true
|
7
|
+
end
|
8
|
+
|
9
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
10
|
+
|
11
|
+
# TODO: find out why in PTS publications filter, some hidden fields are set to nil and others to "0".
|
12
|
+
# If I change it, filter stops working
|
13
|
+
|
14
|
+
|
15
|
+
filterrific do
|
16
|
+
|
17
|
+
# Creates custom scope "filterrific_person". Finds all records that have one of the given values
|
18
|
+
# in :person_id column
|
19
|
+
# Accepts: Person.new, 17, [Person.new, Person.new], [12, 13, 14], [12, 13, Person.new]
|
20
|
+
# scope :filterrific_person, lambda { |persons|
|
21
|
+
# sanitize: convert all entries to an id (integer), convert to array, do nothing if persons.empty?
|
22
|
+
# foreign_key: inspect association to get foreign key
|
23
|
+
# where(:person_id => persons)
|
24
|
+
# }
|
25
|
+
filter :belongs_to => :person
|
26
|
+
|
27
|
+
# Creates custom scope "filterrific_is_active". Finds all records that have one of the given
|
28
|
+
# values for :is_active column
|
29
|
+
# Accepts: "true", true, [true, false], [true, 13, false]
|
30
|
+
# scope :filterrific_is_active, lambda { |values|
|
31
|
+
# sanitize: convert all entries to column type, convert to array, do nothing if values.empty?
|
32
|
+
# where(:is_active => values)
|
33
|
+
# }
|
34
|
+
filter :column => :is_active, :default => true
|
35
|
+
|
36
|
+
# Creates scopes for date/datetime columns.
|
37
|
+
# Possible conditions: :after, :before, :on_or_after, :on_or_before
|
38
|
+
# scope :filterrific_created_at_on_or_after, lambda { |datetime|
|
39
|
+
# datetime = sanitize datetime
|
40
|
+
# return nil if datetime.blank
|
41
|
+
# table_name = get tablename from class
|
42
|
+
# where(['tablename.created_at >= ?', datetime])
|
43
|
+
# }
|
44
|
+
filter :column => :created_at, :condition => :on_or_after, :default => Proc.new { 2.years.ago.beginning_of_year }
|
45
|
+
filter :column => :last_login_on, :condition => :before
|
46
|
+
|
47
|
+
# Creates custom scope "filterrific_some_complex_scope". Uses scope :some_complex_scope
|
48
|
+
# scope :filterrific_some_complex_scope, lambda { |*args|
|
49
|
+
# some_complex_scope(args)
|
50
|
+
# }
|
51
|
+
filter :scope => :some_complex_scope
|
52
|
+
|
53
|
+
# Available options for filter:
|
54
|
+
#
|
55
|
+
# Options for filter type:
|
56
|
+
# :belongs_to: to filter on a belongs_to association
|
57
|
+
# :column: to filter on a column
|
58
|
+
# :scope: to delegate filtering to a scope that is already defined on the class
|
59
|
+
#
|
60
|
+
# General options:
|
61
|
+
# :default: to set the default, can be static value or Proc.new
|
62
|
+
# :name: to change the name for a given filter. The name will still be prefixed with filterrific_prefix
|
63
|
+
#
|
64
|
+
# Possible conditions for :column filters:
|
65
|
+
# * in: contained in set, IN (This is the default condition)
|
66
|
+
# * comparisons: :after, :before, :on_or_after, :on_or_before, >, <, >=, <=
|
67
|
+
# * equals: exactly one, =
|
68
|
+
# * like: LIKE
|
69
|
+
# * between: BETWEEN a AND b
|
70
|
+
|
71
|
+
# Creates custom scope named "filterrific_sort"
|
72
|
+
sort(
|
73
|
+
:sort_keys => [
|
74
|
+
{ :key => :newest_first, :label => "Newest first", :sql => "created_at DESC" },
|
75
|
+
{ :key => :alphabetically, :label => "Name (a-z)", :sql => "name ASC" },
|
76
|
+
],
|
77
|
+
:default => :newest_first,
|
78
|
+
:secondary_sorting => "name ASC" # will be appended to every sort as secondary sort key
|
79
|
+
)
|
80
|
+
|
81
|
+
# Creates custom scope named "filterrific_search"
|
82
|
+
search(
|
83
|
+
:columns => [:name, :email, 'provinces.name'], # default: all string columns
|
84
|
+
:joins => :province,
|
85
|
+
:case_sensitive => false, # adds downcase parts to term_processor and SQL query if false
|
86
|
+
:term_splitter => /\s+/,
|
87
|
+
:wild_card_processor => Proc.new({ |e| "%#{ e }%" }) OR Proc.new({ |e| e.gsub('*', '%') }),
|
88
|
+
:default => "some query",
|
89
|
+
:param_name => "search" # somebody might want to set it to "q"
|
90
|
+
)
|
91
|
+
# Alternative search: delegate to pg_search for fulltext search on Postgres
|
92
|
+
|
93
|
+
# If true, prints auto generated and used scopes, current filterrific params, whether all DB
|
94
|
+
# columns have indices
|
95
|
+
config :debug => true # should there be different log levels? option to set output (log, puts)
|
96
|
+
# Prefix is applied to scopes that are available to filterrific. Note that this is different
|
97
|
+
# from the param_prefix that can be set in the controller config.
|
98
|
+
config :scope_prefix => "filterrific_" # default, somebody might want to shorten or remove prefix
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
scope :some_complex_scope, lambda { |a_value| ... }
|
103
|
+
|
104
|
+
|
105
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
106
|
+
|
107
|
+
|
108
|
+
filterrific do
|
109
|
+
|
110
|
+
# Creates custom scope "filterrific_person". Finds all records that have one of the given values
|
111
|
+
# in :person_ids column
|
112
|
+
# Q: Could I skip the :assciation => true piece? Filterrific could figure this out automatically
|
113
|
+
filter :person, :association => true # instead of true, could be an association name, e.g. :user
|
114
|
+
filter :association => :person # alternative syntax A
|
115
|
+
association :person # alternative syntax B
|
116
|
+
# Creates custom scope "filterrific_active_only". Finds all records that have one of the given
|
117
|
+
# values for :is_active column
|
118
|
+
filter :active_only, :column => :is_active || :some_scope_name, :default => true
|
119
|
+
filter :column => :is_active, :default => true # alternative syntax A
|
120
|
+
column :is_active, :default => true # alternative syntax B
|
121
|
+
# Creates custom scope "filterrific_created_after". Finds all records that have created_at after
|
122
|
+
# the given DateTime
|
123
|
+
filter :created_after, :column => :created_at, :default => Proc.new { 2.years.ago.beginning_of_year }
|
124
|
+
# Creates custom scope "filterrific_complicated_scope". Delegates to an already existing scope
|
125
|
+
# named :complicated_scope_name
|
126
|
+
# Q: How does it know the params expected by :complicated_scope_name?
|
127
|
+
# A: scope :filterrific_complicated_scope_name, lambda { |*attrs| complicated_scope_name(attrs) }
|
128
|
+
filter :complicated_scope, :use_scope => :complicated_scope_name
|
129
|
+
filter :scope => :complicated_scope_name # alternative syntax A
|
130
|
+
scope :complicated_scope_name # alternative syntax B
|
131
|
+
|
132
|
+
# Creates custom scope named "filterrific_sort"
|
133
|
+
sort(
|
134
|
+
:sort_keys => [
|
135
|
+
{ :key => :newest_first, :label => "Newest first", :sql => "created_at DESC" },
|
136
|
+
{ :key => :alphabetically, :label => "Name (a-z)", :sql => "name ASC" },
|
137
|
+
],
|
138
|
+
:default => :newest_first,
|
139
|
+
:secondary_sorting => "name ASC" # will be appended to every sort as secondary sort key
|
140
|
+
)
|
141
|
+
|
142
|
+
# Creates custom scope named "filterrific_search"
|
143
|
+
search(
|
144
|
+
:columns => [:name, :email, 'provinces.name'], # default: all string columns
|
145
|
+
:joins => :province,
|
146
|
+
:case_sensitive => false, # adds downcase parts to term_processor and SQL query if false
|
147
|
+
:term_splitter => /\s+/,
|
148
|
+
:wild_card_processor => Proc.new({ |e| "%#{ e }%" }) OR Proc.new({ |e| e.gsub('*', '%') }),
|
149
|
+
:default => "some query",
|
150
|
+
:param_name => "search" # somebody might want to set it to "q"
|
151
|
+
)
|
152
|
+
|
153
|
+
# If true, prints auto generated and used scopes, current filterrific params, whether all DB
|
154
|
+
# columns have indices
|
155
|
+
config :debug => true # should there be different log levels? option to set output (log, puts)
|
156
|
+
config :param_prefix => "filterrific_" # default, somebody might want to shorten or remove prefix
|
157
|
+
|
158
|
+
auto generate from association
|
159
|
+
auto generate from column
|
160
|
+
delegate to existing scope
|
161
|
+
sort auto or refer
|
162
|
+
search auto or refer
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
scope :complicated_scope_name, lambda { |...| }
|
167
|
+
|
168
|
+
|
169
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
170
|
+
|
171
|
+
filterrific do
|
172
|
+
|
173
|
+
filter :publication_date_min,
|
174
|
+
:use_scope => :publication_date_min,
|
175
|
+
:default => lambda { Date.new(Date.today.year, 1, 1).to_s(:calendar_display_area) }
|
176
|
+
# need to handle date pre-processing (condition_publication_date_for_named_scope)
|
177
|
+
filter :publication_date_max,
|
178
|
+
:column => :publication_date,
|
179
|
+
:condition => :on_or_before,
|
180
|
+
:default => lambda { Date.new(Date.today.year + 3, 12, 31).to_s(:calendar_display_area) }
|
181
|
+
filter :group, :belongs_to => true, :default => Language.all.map(&:id)
|
182
|
+
filter :language, :belongs_to => true
|
183
|
+
filter :owner, :belongs_to => true # could find the association automatically. Don't need belongs_to here
|
184
|
+
filter :person, :use_scope => :with_person
|
185
|
+
filter :programme, :belongs_to => true, :default => Programme.all.map(&:id)
|
186
|
+
filter :publication_status, :belongs_to => true, :default => [1, 2, 5, 7]
|
187
|
+
filter :publication_type,
|
188
|
+
:belongs_to => true,
|
189
|
+
:default => PublicationType.all.map(&:id) - [PublicationType.find_partner.nil_or(:id)]
|
190
|
+
filter :role_type, :use_scope => :with_role_type
|
191
|
+
filter :department, :use_scope => :for_department
|
192
|
+
|
193
|
+
# or just referencing stuff that already is declared in the class
|
194
|
+
belongs_to :group # creates scope 'filterrific_with_group'
|
195
|
+
belongs_to :language, :default => Language.all.map(&:id)
|
196
|
+
belongs_to :owner, :default => Programme.all.map(&:id)
|
197
|
+
belongs_to :programme
|
198
|
+
belongs_to :publication_status, :default => [1, 2, 5, 7], :param_name => :status
|
199
|
+
belongs_to :publication_type, :default => PublicationType.all.map(&:id) - [PublicationType.find_partner.nil_or(:id)]
|
200
|
+
|
201
|
+
scope :publication_date_min, :default => lambda { Date.new(Date.today.year, 1, 1).to_s(:calendar_display_area) }
|
202
|
+
scope :publication_date_max, :default => lambda { Date.new(Date.today.year + 3, 12, 31).to_s(:calendar_display_area) }
|
203
|
+
scope :with_person
|
204
|
+
scope :with_role_type
|
205
|
+
scope :for_department
|
206
|
+
scope :with_sales_item_status, :default => %w[sales_item non_sales_item],
|
207
|
+
scope :with_commercial_title_status, :default => %w[commercial_title non_commercial_title]
|
208
|
+
|
209
|
+
column: checks for inclusion
|
210
|
+
|
211
|
+
flag: the sales item checkboxes in PTS
|
212
|
+
|
213
|
+
search :columns => [:short_title], :param_name => "search_short_title"
|
214
|
+
|
215
|
+
# Two modes: auto generate or manual. If auto, can generate two directions. Manual will always
|
216
|
+
# generate one direction only.
|
217
|
+
# Distinction: :order-option given? ? :manual : :auto
|
218
|
+
#
|
219
|
+
# common options: :key, :label (default: key.to_s.titleize), :apply_secondary_sorting (default: true)
|
220
|
+
# auto only options: :directions (default: [:asc, :desc]),
|
221
|
+
# manual only options: :order, :joins
|
222
|
+
sort(
|
223
|
+
[
|
224
|
+
{ :key => :newest_first, :label => "Newest first", :order => "publications.created_at DESC" },
|
225
|
+
{ :key => :alphabetically, :label => "Name (a-z)", :order => "users.name ASC", :joins => :users }
|
226
|
+
# creates sort_options extent_asc and extent_desc. Label is defined here on each sort_key.
|
227
|
+
# Would be cumbersome in view.
|
228
|
+
# Creates sort: order("publications.extent ASC, <secondary sort>"), label: "Extent Asc" and
|
229
|
+
# order("publications.extent DESC, <secondary sort>"), label: "Extent Desc"
|
230
|
+
{ :key => :extent, :directions => [:asc, :desc] }, # [:asc, :desc], :asc, :desc, [:asc]
|
231
|
+
{ :key => :id },
|
232
|
+
{ :key => :owner_id },
|
233
|
+
{ :key => :paf_status_id },
|
234
|
+
{ :key => :project_manager_name, :label => "PM" },
|
235
|
+
{ :key => :publication_date },
|
236
|
+
{ :key => :publication_type },
|
237
|
+
{ :key => :sales_item },
|
238
|
+
{ :key => :short_title },
|
239
|
+
{ :key => :updated_at, :apply_secondary_sorting => false },
|
240
|
+
{ :key => :programme_asc, :order => "lower(programmes.name) ASC", :joins => :programme },
|
241
|
+
{ :key => :language_asc, :order => "lower(languages.name) ASC", :joins => :language },
|
242
|
+
{ :key => :status, :order => "lower(publication_statuses.name) ASC", :joins => :publication_status }
|
243
|
+
],
|
244
|
+
:default => :newest_first,
|
245
|
+
:param_name => :sort,
|
246
|
+
:case_sensitive => false # this uses the lower() SQL modifier around any string columns for auto generated search options
|
247
|
+
:secondary_sorting => {
|
248
|
+
:order => "publications.publication_date asc, lower(publications.short_title) asc, publications.id asc",
|
249
|
+
:joins => :paf_status
|
250
|
+
}
|
251
|
+
)
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
# have to use :include instead of :joins for :roles. If I use :joins, it does an inner join and
|
257
|
+
# returns duplicates for publications. Same for :with_role_type scope.
|
258
|
+
# roles is a habtm relation with publication.
|
259
|
+
named_scope :with_person, lambda{ |person_ids|
|
260
|
+
{
|
261
|
+
:conditions => ["roles.person_id IN (?)", [*person_ids].map(&:to_i)],
|
262
|
+
:include => :roles
|
263
|
+
}
|
264
|
+
}
|
265
|
+
named_scope :with_role_type, lambda{ |role_type_ids|
|
266
|
+
{
|
267
|
+
:conditions => ["roles.role_type_id IN (?)", [*role_type_ids].map(&:to_i)],
|
268
|
+
:include => :roles
|
269
|
+
}
|
270
|
+
}
|
271
|
+
named_scope :for_department, lambda{ |department_ids|
|
272
|
+
phase_boundary_event_types = Department.find(
|
273
|
+
[*department_ids].map(&:to_i)
|
274
|
+
).map(&:phase_boundary_event_types).flatten
|
275
|
+
{ :conditions => ["events.event_type_id IN (?)", phase_boundary_event_types.map(&:id)], :joins => :events }
|
276
|
+
}
|
277
|
+
named_scope :with_sales_item_status, lambda{ |statuses|
|
278
|
+
v = ['1 = 2'] # never true, used if no checkbox is checked ("0")
|
279
|
+
v << 'publications.sales_item = 1' if statuses.include?("sales_item")
|
280
|
+
v << 'publications.sales_item != 1' if statuses.include?("non_sales_item")
|
281
|
+
{ :conditions => v.join(' OR ') }
|
282
|
+
}
|
283
|
+
named_scope :with_commercial_title_status, lambda{ |statuses|
|
284
|
+
v = ['1 = 2'] # never true, used if no checkbox is checked ("0")
|
285
|
+
v << 'publications.service_category_id = 1' if statuses.include?("commercial_title")
|
286
|
+
v << 'publications.service_category_id != 1' if statuses.include?("non_commercial_title")
|
287
|
+
{ :conditions => v.join(' OR ') }
|
288
|
+
}
|
289
|
+
|
290
|
+
|
291
|
+
|
292
|
+
|
293
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
# Defines a filter available to Filterrific
|
308
|
+
#
|
309
|
+
# Filters are used to retrieve a subset of all records available, based on a given criterion.
|
310
|
+
# Filterrific uses Rails' scopes for this purpose. For each filter specified, Filterrific will
|
311
|
+
# create a new scope with the name "filterrific_#{ filter_key }".
|
312
|
+
#
|
313
|
+
# Filter type option
|
314
|
+
#
|
315
|
+
# This option tells Filterrific about the kind of filter required. If not given, F tries to figure
|
316
|
+
# out the filter type from the filter_key, in the following order:
|
317
|
+
#
|
318
|
+
# 1) ActiveRecord association on the model with the same name as filter_key
|
319
|
+
# 2) Column in the model's table with the same name as filter_key
|
320
|
+
# 3) Existing scope on the model with the same name as filter_key
|
321
|
+
#
|
322
|
+
# Accepts:
|
323
|
+
#
|
324
|
+
# * :association(better belongs_to???) - this filter acts on an ActiveRecord association, typically a belongs_to.
|
325
|
+
# Expects: true (F uses the filter_key as association name) or the name of the association as
|
326
|
+
# Symbol or String.
|
327
|
+
# * :column - this filter acts on a column on this model's table. Filterrific looks at the column
|
328
|
+
# type to determine what kind of scope is required. See below for column_type specific options.
|
329
|
+
# Expects: true (F uses the filter_key as column_name) or the name of the column as Symbol or String.
|
330
|
+
# * :use_scope - accepts Symbod/String to delegate to an existing scope that is already defined on the
|
331
|
+
# model. Alternatively accepts a Proc to define a scope within filterrific. Use the same syntax
|
332
|
+
# as for Rails scopes.
|
333
|
+
# Expects: true (F uses the filter_key as scope_name) or the name of the scope as Symbol or String.
|
334
|
+
#
|
335
|
+
# General options
|
336
|
+
#
|
337
|
+
# These options are applicable to all filter types
|
338
|
+
#
|
339
|
+
# * :default - the default value for this filter. Used on first call and after reset_filterrific.
|
340
|
+
# Set this on any filter that has a default setting.
|
341
|
+
add param name?
|
342
|
+
#
|
343
|
+
# SQL Options
|
344
|
+
#
|
345
|
+
# These options are applicable for filters that generate SQL
|
346
|
+
#
|
347
|
+
# * :joins => tables to join
|
348
|
+
# * :includes => tables to include
|
349
|
+
#
|
350
|
+
# Date filter options
|
351
|
+
#
|
352
|
+
# These options are applicable to a filter of type :column where the column is of type date.
|
353
|
+
#
|
354
|
+
# * :condition - Expects one of :before, :after, :between, :on_or_after, :on_or_before, :at_or_after, :at_or_before
|
355
|
+
#
|
356
|
+
# @param [Symbol, String] filter_key the key to be used for this filter
|
357
|
+
# @param [Hash] opts the options to specify this filter
|
358
|
+
# @return ?
|
359
|
+
#
|
360
|
+
filter(filter_key, filter_type, opts = {})
|
361
|
+
end
|
362
|
+
|
363
|
+
|
364
|
+
# Defines sorting for Filterrific
|
365
|
+
#
|
366
|
+
# Sort is a special type of filter. It is used to allow a user to choose the sorting of a collection.
|
367
|
+
#
|
368
|
+
# Uses sort_key as internal identifier and also as name for the form param. Creates a scope named
|
369
|
+
# "filterrific_#{ sort_key }".
|
370
|
+
#
|
371
|
+
# Options if using Filterrific internal sort
|
372
|
+
#
|
373
|
+
# * :sort_keys - A hash for each sort key with the following options:
|
374
|
+
# ** :key - internal name for this sort key. If no :sql given, sorts by column with this name
|
375
|
+
# ** :label - label for this sort key, used in views. ?? Shouldn't this be in view helpers?'
|
376
|
+
# ** :sql - a SQL fragment used as is to specify sorting
|
377
|
+
# ** :joins - joins to be performed for sorting
|
378
|
+
# * :secondary_sorting - sort_key that will be appended to every sort as secondary sort key
|
379
|
+
# * :default - the :key of the default sort order
|
380
|
+
# * :joins - joins to be added to every sort operation (might be required for secondary sorting)
|
381
|
+
#
|
382
|
+
# Options if using existing scope for sort
|
383
|
+
#
|
384
|
+
# * :scope - the name of an existing scope to be used for sort
|
385
|
+
# * :default - the :key of the default sort order
|
386
|
+
#
|
387
|
+
# @param [Array<Hash>] sort_options the sort options to be offered
|
388
|
+
# @param [Hash] opts the options to specify sorting
|
389
|
+
# @return ?
|
390
|
+
#
|
391
|
+
def sort(sort_options, opts = {})
|
392
|
+
end
|
393
|
+
|
394
|
+
|
395
|
+
# Defines search for Filterrific.
|
396
|
+
# Search is a special type of filter. It is used to retrieve records from the database that match
|
397
|
+
# a given search string. This is typically not as powerful as an indexed search engine, however
|
398
|
+
# it can be sufficient in a large number of use cases and is a lot simpler to set up than an index
|
399
|
+
# search server like Solr or Lucene (verify search server list!!!).
|
400
|
+
#
|
401
|
+
# Uses search_key as internal identifier and also as name for the form param. Creates a scope named
|
402
|
+
# "filterrific_#{ search_key }".
|
403
|
+
#
|
404
|
+
# Options if using Filterrific internal search
|
405
|
+
#
|
406
|
+
# * :columns => [:name, :email, 'provinces.name'], # default: all string columns
|
407
|
+
# * :joins => :province
|
408
|
+
# * :case_sensitive => false, (adds downcase parts to term_processor and SQL query if false)
|
409
|
+
# * :term_splitter => /\s+/
|
410
|
+
# * :wild_card_processor => Proc.new({ |e| "%#{ e }%" }) OR Proc.new({ |e| e.gsub('*', '%') })
|
411
|
+
# * :default - the value for the default search string. Default: nil
|
412
|
+
#
|
413
|
+
# Options if using existing scope for search
|
414
|
+
#
|
415
|
+
# * :scope => :fancy_search # name of an existing scope to be used for search
|
416
|
+
# * :default - the value for the default search string. Default: nil
|
417
|
+
#
|
418
|
+
# @param [Symbol, String] search_key the key to be used for searching
|
419
|
+
# @param [Hash] opts the options to specify searching
|
420
|
+
# @return ?
|
421
|
+
#
|
422
|
+
# * CVIMS Content looks like a good and general solution
|
423
|
+
#
|
424
|
+
def search(search_key, opts = {})
|
425
|
+
end
|
426
|
+
|
427
|
+
|
428
|
+
# Configures one or more aspects of Filterrific.
|
429
|
+
#
|
430
|
+
# Available Config options
|
431
|
+
#
|
432
|
+
# * :debug => true or output type (log, stdout)
|
433
|
+
# * :sql_type => :mysql (or :postgresql), possible oracle? Determines how search is handled (regex
|
434
|
+
# vs. like), and any other differences. Could we use Rails' DB connectors for this?
|
435
|
+
#
|
436
|
+
# @param [Hash] opts the config options
|
437
|
+
# @return ?
|
438
|
+
#
|
439
|
+
def config(opts = {})
|
440
|
+
end
|
441
|
+
|
442
|
+
|
443
|
+
|
444
|
+
|
445
|
+
Auto generated scopes for author:
|
446
|
+
|
447
|
+
* belongs_to: scope :filterrific_with_author_ids, lambda { |author_ids| where({ :author_id => *[author_ids] }
|
448
|
+
* has_many: scope exists?
|
449
|
+
* collection
|
450
|
+
* attribute [String]
|
451
|
+
* attribute [Numeric]
|
452
|
+
* attribute [Date, DateTime]
|
453
|
+
* attribute [Boolean,TinyInt]
|
454
|
+
* attribute [Text]
|
455
|
+
*
|
456
|
+
|
457
|
+
Each type uses a kind of Filterrific::Matcher:
|
458
|
+
|
459
|
+
* search
|
460
|
+
* date_time
|
461
|
+
* foreign_key
|
462
|
+
|
463
|
+
|
464
|
+
|
465
|
+
MODEL
|
466
|
+
=====
|
467
|
+
|
468
|
+
filterrific do
|
469
|
+
|
470
|
+
associations do
|
471
|
+
person # creates a scope for filterrific
|
472
|
+
state, :default => [1,2,3,4], :type => :select, :multiple => 4
|
473
|
+
end
|
474
|
+
|
475
|
+
scopes do
|
476
|
+
active_only, :default => true # refers to already defined scope
|
477
|
+
search, :as => "q" (optional param name override)
|
478
|
+
sorted_by, :default => "created_at_desc"
|
479
|
+
end
|
480
|
+
|
481
|
+
config :debug => true # prints auto generated and used scopes, current filterrific params, whether all DB columns have indices
|
482
|
+
config ... can't think of any other config options yet.
|
483
|
+
end
|
484
|
+
|
485
|
+
scope :search, ...
|
@@ -0,0 +1,49 @@
|
|
1
|
+
All view related aspects of filterrific are handled via the view API:
|
2
|
+
|
3
|
+
<%= filterrific_form_for @filterrific do |f| %>
|
4
|
+
|
5
|
+
<%= f.select :author, # look at formtastic for inspiration. It auto generates a bunch of stuff %>
|
6
|
+
Options for select:
|
7
|
+
* multiple => false
|
8
|
+
* allow_blank => true or "-- Any --"
|
9
|
+
* value_method => :id
|
10
|
+
* label_method => %w[name title label]
|
11
|
+
* collection =>
|
12
|
+
|
13
|
+
<%= f.boolean :published %>
|
14
|
+
Renders a checkbox
|
15
|
+
|
16
|
+
<%= f.search %>
|
17
|
+
Renders a text box for searching
|
18
|
+
Options:
|
19
|
+
* JS: event: keydown, delay, min_chars
|
20
|
+
* wildcards here or in model?
|
21
|
+
|
22
|
+
<%= f.date or f.datetime %>
|
23
|
+
Renders a text box for date selection. Integrate with jQuery UI calendar select
|
24
|
+
* date is date only
|
25
|
+
* datetime also adds time
|
26
|
+
|
27
|
+
<%= f.radio %>
|
28
|
+
Renders a radio button to select one of many options
|
29
|
+
Options
|
30
|
+
* label_methods => see select
|
31
|
+
* value_method => :id
|
32
|
+
* collection =>
|
33
|
+
|
34
|
+
<%= f.sort %>
|
35
|
+
Renders a select for choosing sort options
|
36
|
+
Options
|
37
|
+
* collection =>
|
38
|
+
|
39
|
+
<% end %>
|
40
|
+
|
41
|
+
|
42
|
+
<%= filterrific_info(options) %>
|
43
|
+
|
44
|
+
Options:
|
45
|
+
* :print_all_available_filters
|
46
|
+
* :print_current_filter_params
|
47
|
+
|
48
|
+
|
49
|
+
Also have to add JS to observe the form. Use generator for that?
|
data/doc/documentation.md
CHANGED
@@ -14,8 +14,10 @@
|
|
14
14
|
|
15
15
|
* Scenarios
|
16
16
|
* Saved search (persist FilterrificParamSet in DB)
|
17
|
-
* Will paginate integration
|
17
|
+
* Will paginate/kaminari integration
|
18
18
|
* Session persistence
|
19
|
+
* Interface for JS client side app to get collections of data via JSON REST
|
20
|
+
* integrate with PG fulltext search (pg_search)
|
19
21
|
* Defining Scopes
|
20
22
|
* Belongs_to
|
21
23
|
* Has_many
|
@@ -27,6 +29,6 @@
|
|
27
29
|
|
28
30
|
## Requirements
|
29
31
|
|
30
|
-
* Rails3
|
32
|
+
* Rails3 (or 3.1?)
|
31
33
|
|
32
34
|
|
data/doc/ideas.txt
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
20110418: Look at this when building API: https://github.com/ryan-allen/lispy
|
2
|
+
|
3
|
+
|
4
|
+
20110414 Related project:
|
5
|
+
|
6
|
+
* https://github.com/plataformatec/has_scope
|
7
|
+
|
8
|
+
20110221 Promotion:
|
9
|
+
|
10
|
+
* railscasts (even ask for review/feedback)
|
11
|
+
* railsinside
|
12
|
+
* ruby toolbox
|
13
|
+
|
14
|
+
|
15
|
+
20110205: figuring out best prefix for namespacing filterrific
|
16
|
+
|
17
|
+
balance between shortness and expression:
|
18
|
+
|
19
|
+
f
|
20
|
+
fc
|
21
|
+
ft
|
22
|
+
frc
|
23
|
+
ftf
|
24
|
+
fifc
|
25
|
+
flfc
|
26
|
+
frfc
|
27
|
+
ftfc
|
28
|
+
ftrfc
|
29
|
+
fltrfc
|
30
|
+
filtrfc
|
31
|
+
filterrific
|
32
|
+
|
33
|
+
20110112: see if I can learn something here:
|
34
|
+
http://www.idolhands.com/ruby-on-rails/guides-tips-and-tutorials/add-filters-to-views-using-named-scopes-in-rails
|
35
|
+
|
36
|
+
|
37
|
+
20101227: get inspiration from this project: https://github.com/neerajdotname/admin_data
|
38
|
+
look especially at their query builder in the heroku demo project (add conditions like Finder search)
|
39
|
+
|
40
|
+
|
1
41
|
Glean specific code from these projects:
|
2
42
|
|
3
43
|
20100224 CVIMS
|
@@ -6,28 +46,6 @@ Glean specific code from these projects:
|
|
6
46
|
201001 Quentin-rails-backend
|
7
47
|
stratadocs (list starts with self as AR proxy)
|
8
48
|
|
9
|
-
MODEL
|
10
|
-
=====
|
11
|
-
|
12
|
-
filterrific do
|
13
|
-
|
14
|
-
associations do
|
15
|
-
person # creates a scope for filterrific
|
16
|
-
state, :default => [1,2,3,4], :type => :select, :multiple => 4
|
17
|
-
end
|
18
|
-
|
19
|
-
scopes do
|
20
|
-
active_only, :default => true # refers to already defined scope
|
21
|
-
search, :as => "q" (optional param name override)
|
22
|
-
sorted_by, :default => "created_at_desc"
|
23
|
-
end
|
24
|
-
|
25
|
-
persist_in_session false # overrides global filterrific settings
|
26
|
-
end
|
27
|
-
|
28
|
-
scope :search, ...
|
29
|
-
|
30
|
-
Only filters defined in filterrific will be exposed via URL. Other scopes will not be accessible
|
31
49
|
|
32
50
|
view
|
33
51
|
(skip these for now?)
|
@@ -36,30 +54,8 @@ integrate with formtastic?
|
|
36
54
|
|
37
55
|
|
38
56
|
|
39
|
-
CONTROLLER
|
40
|
-
==========
|
41
|
-
|
42
|
-
def index
|
43
|
-
@filter_options = init_filterrific(Publication, :publications_list)
|
44
|
-
@publications = Publication.filterrific(@filter_options).paginate....
|
45
|
-
@publications = current_user.publications.filterrific(@filter_options).paginate....
|
46
|
-
...
|
47
|
-
end
|
48
|
-
|
49
|
-
def init_filterrific(klass, scope = nil)
|
50
|
-
scope_name ||= klass.to_s.underscore # use resource class name as default scope name
|
51
|
-
filter_options_hash = params[:filter_options]
|
52
|
-
filter_options_hash ||= session[scope_name] if filterrific.persist_in_session
|
53
|
-
@filter_options = Filterrific.new(Publication, params[:filter_options])
|
54
|
-
session[scope_name] = @filter_options.to_hash if filterrific.persist_in_session # (store sanitized options). Maybe just define marshal dump? skip to_hash
|
55
|
-
end
|
56
57
|
|
57
58
|
|
58
|
-
Filterrific CONFIG
|
59
|
-
==================
|
60
|
-
|
61
|
-
Settings:
|
62
|
-
* persist_in_session
|
63
59
|
|
64
60
|
|
65
61
|
|
data/doc/todo.md
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
To make it work on Rails 3.1:
|
2
|
+
|
3
|
+
* follow kaminari gem for recipe
|
4
|
+
* implement new model api
|
5
|
+
* leave view and controller as is
|
6
|
+
* bump version to 1.0.0 (not backwards compatible)
|
7
|
+
|
8
|
+
Later:
|
9
|
+
* build filterrific-recipes on github wiki
|
10
|
+
* update readme
|
11
|
+
* update view and controller apis
|
12
|
+
|
13
|
+
|
1
14
|
# Implementation Plan for Filterrific
|
2
15
|
|
3
16
|
## Version 0.1.0: Rebuild current Rails2 functionality
|
4
17
|
|
5
18
|
## Add DSL and scope generator
|
6
|
-
|
19
|
+
## Write specs (http://avdi.org/devblog/2011/04/07/rspec-is-for-the-literate/ also read comments about be_...!)
|
7
20
|
## Add Filterrific form builder
|
8
21
|
|
data/filterrific.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{filterrific}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jo Hund"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-11-09}
|
13
13
|
s.description = %q{
|
14
14
|
The Rails User Interface solution for filtering your ActiveRecord lists:
|
15
15
|
|
@@ -23,47 +23,44 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.email = %q{jhund@clearcove.ca}
|
24
24
|
s.extra_rdoc_files = [
|
25
25
|
"LICENSE",
|
26
|
-
|
26
|
+
"README.rdoc"
|
27
27
|
]
|
28
28
|
s.files = [
|
29
|
-
".
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
29
|
+
"CHANGELOG.md",
|
30
|
+
"LICENSE",
|
31
|
+
"README.rdoc",
|
32
|
+
"Rakefile",
|
33
|
+
"VERSION",
|
34
|
+
"doc/Overview diagram.graffle/QuickLook/Preview.pdf",
|
35
|
+
"doc/Overview diagram.graffle/QuickLook/Thumbnail.tiff",
|
36
|
+
"doc/Overview diagram.graffle/data.plist",
|
37
|
+
"doc/Overview diagram.graffle/image1.tiff",
|
38
|
+
"doc/development_notes/api_design.txt",
|
39
|
+
"doc/development_notes/controller_api.txt",
|
40
|
+
"doc/development_notes/model_api.rb",
|
41
|
+
"doc/development_notes/view_api.txt",
|
42
|
+
"doc/documentation.md",
|
43
|
+
"doc/ideas.txt",
|
44
|
+
"doc/todo.md",
|
45
|
+
"doc/workflow.md",
|
46
|
+
"filterrific.gemspec",
|
47
|
+
"lib/filterrific.rb",
|
48
|
+
"lib/filterrific/model_mixin.rb",
|
49
|
+
"lib/filterrific/param_set.rb",
|
50
|
+
"lib/filterrific/railtie.rb",
|
51
|
+
"lib/filterrific/view_helpers.rb",
|
52
|
+
"test/helper.rb",
|
53
|
+
"test/test_filterrific.rb"
|
51
54
|
]
|
52
55
|
s.homepage = %q{http://github.com/jhund/filterrific}
|
53
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
54
56
|
s.require_paths = ["lib"]
|
55
|
-
s.rubygems_version = %q{1.
|
57
|
+
s.rubygems_version = %q{1.5.2}
|
56
58
|
s.summary = %q{The Rails User Interface solution for filtering your ActiveRecord lists.}
|
57
|
-
s.test_files = [
|
58
|
-
"test/helper.rb",
|
59
|
-
"test/test_filterrific.rb"
|
60
|
-
]
|
61
59
|
|
62
60
|
if s.respond_to? :specification_version then
|
63
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
61
|
s.specification_version = 3
|
65
62
|
|
66
|
-
if Gem::Version.new(Gem::
|
63
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
64
|
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
68
65
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
69
66
|
else
|
@@ -8,12 +8,17 @@ module Filterrific::ModelMixin
|
|
8
8
|
|
9
9
|
# Adds filterrific behavior to class when called like so:
|
10
10
|
#
|
11
|
-
# filterrific
|
11
|
+
# filterrific(
|
12
|
+
# :defaults => { :sorted_by => "created_at_asc" },
|
13
|
+
# :scope_names => [:sorted_by, :search_query, :with_state]
|
14
|
+
# )
|
12
15
|
#
|
13
16
|
def filterrific(options = {})
|
14
17
|
# send :include, InstanceMethods
|
15
18
|
cattr_accessor :default_filterrific_params
|
19
|
+
cattr_accessor :filterrific_scope_names
|
16
20
|
self.default_filterrific_params = (options[:defaults] || {}).stringify_keys
|
21
|
+
self.filterrific_scope_names = (options[:scope_names] || []).stringify_keys
|
17
22
|
end
|
18
23
|
|
19
24
|
# Returns AR relation based on given filterrific_param_set.
|
@@ -38,11 +43,6 @@ module Filterrific::ModelMixin
|
|
38
43
|
ar_proxy
|
39
44
|
end
|
40
45
|
|
41
|
-
# Returns Array all filter scope names
|
42
|
-
def filterrific_scope_names
|
43
|
-
scopes.map{ |s| s.first.to_s }
|
44
|
-
end
|
45
|
-
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filterrific
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
5
6
|
segments:
|
7
|
+
- 1
|
6
8
|
- 0
|
7
|
-
- 2
|
8
9
|
- 0
|
9
|
-
version: 0.
|
10
|
+
version: 1.0.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Jo Hund
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-11-09 00:00:00 -08:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: thoughtbot-shoulda
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
27
30
|
segments:
|
28
31
|
- 0
|
29
32
|
version: "0"
|
@@ -33,9 +36,11 @@ dependencies:
|
|
33
36
|
name: yard
|
34
37
|
prerelease: false
|
35
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
36
40
|
requirements:
|
37
41
|
- - ">="
|
38
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
39
44
|
segments:
|
40
45
|
- 0
|
41
46
|
version: "0"
|
@@ -51,7 +56,6 @@ extra_rdoc_files:
|
|
51
56
|
- LICENSE
|
52
57
|
- README.rdoc
|
53
58
|
files:
|
54
|
-
- .gitignore
|
55
59
|
- CHANGELOG.md
|
56
60
|
- LICENSE
|
57
61
|
- README.rdoc
|
@@ -61,6 +65,10 @@ files:
|
|
61
65
|
- doc/Overview diagram.graffle/QuickLook/Thumbnail.tiff
|
62
66
|
- doc/Overview diagram.graffle/data.plist
|
63
67
|
- doc/Overview diagram.graffle/image1.tiff
|
68
|
+
- doc/development_notes/api_design.txt
|
69
|
+
- doc/development_notes/controller_api.txt
|
70
|
+
- doc/development_notes/model_api.rb
|
71
|
+
- doc/development_notes/view_api.txt
|
64
72
|
- doc/documentation.md
|
65
73
|
- doc/ideas.txt
|
66
74
|
- doc/todo.md
|
@@ -78,31 +86,34 @@ homepage: http://github.com/jhund/filterrific
|
|
78
86
|
licenses: []
|
79
87
|
|
80
88
|
post_install_message:
|
81
|
-
rdoc_options:
|
82
|
-
|
89
|
+
rdoc_options: []
|
90
|
+
|
83
91
|
require_paths:
|
84
92
|
- lib
|
85
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
86
95
|
requirements:
|
87
96
|
- - ">="
|
88
97
|
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
89
99
|
segments:
|
90
100
|
- 0
|
91
101
|
version: "0"
|
92
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
93
104
|
requirements:
|
94
105
|
- - ">="
|
95
106
|
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
96
108
|
segments:
|
97
109
|
- 0
|
98
110
|
version: "0"
|
99
111
|
requirements: []
|
100
112
|
|
101
113
|
rubyforge_project:
|
102
|
-
rubygems_version: 1.
|
114
|
+
rubygems_version: 1.5.2
|
103
115
|
signing_key:
|
104
116
|
specification_version: 3
|
105
117
|
summary: The Rails User Interface solution for filtering your ActiveRecord lists.
|
106
|
-
test_files:
|
107
|
-
|
108
|
-
- test/test_filterrific.rb
|
118
|
+
test_files: []
|
119
|
+
|