filterrific 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|