ransack 2.6.0 → 3.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 +4 -4
- data/.nojekyll +0 -0
- data/CHANGELOG.md +75 -13
- data/README.md +45 -1039
- data/docs/.gitignore +20 -0
- data/docs/.nojekyll +0 -0
- data/docs/babel.config.js +3 -0
- data/docs/blog/2022-03-27-ransack-3.0.0.md +20 -0
- data/docs/docs/getting-started/_category_.json +4 -0
- data/docs/docs/getting-started/advanced-mode.md +46 -0
- data/docs/docs/getting-started/configuration.md +47 -0
- data/docs/docs/getting-started/search-matches.md +67 -0
- data/docs/docs/getting-started/simple-mode.md +284 -0
- data/docs/docs/getting-started/sorting.md +79 -0
- data/docs/docs/getting-started/using-predicates.md +282 -0
- data/docs/docs/going-further/_category_.json +4 -0
- data/docs/docs/going-further/associations.md +70 -0
- data/docs/docs/going-further/custom-predicates.md +52 -0
- data/docs/docs/going-further/documentation.md +31 -0
- data/docs/docs/going-further/exporting-to-csv.md +49 -0
- data/docs/docs/going-further/external-guides.md +57 -0
- data/docs/docs/going-further/form-customisation.md +63 -0
- data/docs/docs/going-further/i18n.md +53 -0
- data/docs/{img → docs/going-further/img}/create_release.png +0 -0
- data/docs/docs/going-further/merging-searches.md +41 -0
- data/docs/docs/going-further/other-notes.md +428 -0
- data/docs/docs/going-further/ransackers.md +331 -0
- data/docs/docs/going-further/release_process.md +36 -0
- data/docs/docs/going-further/saving-queries.md +82 -0
- data/docs/docs/going-further/searching-postgres.md +57 -0
- data/docs/docs/intro.md +99 -0
- data/docs/docusaurus.config.js +108 -0
- data/docs/package-lock.json +9207 -0
- data/docs/package.json +37 -0
- data/docs/sidebars.js +31 -0
- data/docs/src/components/HomepageFeatures/index.js +64 -0
- data/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- data/docs/src/css/custom.css +39 -0
- data/docs/src/pages/index.module.css +23 -0
- data/docs/src/pages/markdown-page.md +7 -0
- data/docs/static/.nojekyll +0 -0
- data/docs/static/img/docusaurus.png +0 -0
- data/docs/static/img/favicon.ico +0 -0
- data/docs/static/img/logo.svg +1 -0
- data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
- data/docs/static/img/tutorial/localeDropdown.png +0 -0
- data/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- data/docs/static/img/undraw_docusaurus_react.svg +170 -0
- data/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- data/{logo → docs/static/logo}/ransack-h.png +0 -0
- data/{logo → docs/static/logo}/ransack-h.svg +0 -0
- data/{logo → docs/static/logo}/ransack-v.png +0 -0
- data/{logo → docs/static/logo}/ransack-v.svg +0 -0
- data/{logo → docs/static/logo}/ransack.png +0 -0
- data/{logo → docs/static/logo}/ransack.svg +0 -0
- data/docs/yarn.lock +7671 -0
- data/lib/ransack/adapters/active_record/base.rb +0 -2
- data/lib/ransack/adapters/active_record/context.rb +1 -0
- data/lib/ransack/helpers/form_helper.rb +10 -2
- data/lib/ransack/search.rb +2 -2
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +2 -2
- data/spec/ransack/adapters/active_record/base_spec.rb +10 -1
- data/spec/ransack/helpers/form_helper_spec.rb +32 -0
- data/spec/ransack/search_spec.rb +23 -0
- data/spec/support/schema.rb +16 -0
- metadata +58 -12
- data/docs/release_process.md +0 -17
@@ -0,0 +1,282 @@
|
|
1
|
+
---
|
2
|
+
title: Using Predicates
|
3
|
+
---
|
4
|
+
|
5
|
+
The primary method of searching in Ransack is by using what is known as *predicates*.
|
6
|
+
|
7
|
+
Predicates are used within Ransack search queries to determine what information to
|
8
|
+
match. For instance, the `cont` predicate will check to see if an attribute called
|
9
|
+
"first_name" contains a value using a wildcard query:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
>> User.ransack(first_name_cont: 'Rya').result.to_sql
|
13
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Rya%')
|
14
|
+
```
|
15
|
+
|
16
|
+
You can also combine predicates for OR queries:
|
17
|
+
```ruby
|
18
|
+
>> User.ransack(first_name_or_last_name_cont: 'Rya').result.to_sql
|
19
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Rya%'
|
20
|
+
OR "users"."last_name" LIKE '%Rya%')
|
21
|
+
```
|
22
|
+
|
23
|
+
The syntax for `OR` queries on an associated model is not immediately obvious, but makes sense. Assuming a `User` `has_one` `Account` and the `Account` has `attributes` `foo` and `bar`:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
>> User.ransack(account_foo_or_account_bar: 'val').result.to_sql
|
27
|
+
=> SELECT "users".* FROM "users" INNER JOIN accounts ON accounts.user_id = users.id WHERE ("accounts.foo LIKE '%val%' OR accounts.bar LIKE '%val%')
|
28
|
+
```
|
29
|
+
|
30
|
+
Below is a list of the built-in predicates of Ransack and their opposites. You may already
|
31
|
+
be familiar with some of the predicates, as they also exist in the ARel library.
|
32
|
+
|
33
|
+
If you want to add your own, please
|
34
|
+
see the [[Custom-Predicates|Custom Predicates]] page.
|
35
|
+
|
36
|
+
**Please note:** any attempt to use a predicate for an attribute that does not exist will
|
37
|
+
*silently fail*. For instance, this will not work when there is no `name` attribute:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
>> User.ransack(name_cont: 'Rya').result.to_sql
|
41
|
+
=> "SELECT "users".* FROM "users"
|
42
|
+
```
|
43
|
+
|
44
|
+
## eq (equals)
|
45
|
+
|
46
|
+
The `eq` predicate returns all records where a field is *exactly* equal to a given value:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
>> User.ransack(first_name_eq: 'Ryan').result.to_sql
|
50
|
+
=> SELECT "users".* FROM "users" WHERE "users"."first_name" = 'Ryan'
|
51
|
+
```
|
52
|
+
|
53
|
+
**Opposite: `not_eq`**
|
54
|
+
|
55
|
+
## matches
|
56
|
+
|
57
|
+
The `matches` predicate returns all records where a field is like a given value:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
>> User.ransack(first_name_matches: 'Ryan').result.to_sql
|
61
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE 'Ryan')
|
62
|
+
```
|
63
|
+
|
64
|
+
On Postgres, the case-insensitive ILIKE will be used.
|
65
|
+
|
66
|
+
**Opposite: `does_not_match`**
|
67
|
+
|
68
|
+
*Note: If you want to do wildcard matching, you may be looking for the `cont`/`not_cont`
|
69
|
+
predicates instead.*
|
70
|
+
|
71
|
+
## lt (less than)
|
72
|
+
|
73
|
+
The `lt` predicate returns all records where a field is less than a given value:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
>> User.ransack(age_lt: 25).result.to_sql
|
77
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."age" < 25)
|
78
|
+
```
|
79
|
+
|
80
|
+
**Opposite: `gteq` (greater than or equal to)**
|
81
|
+
|
82
|
+
## lteq (less than or equal to)
|
83
|
+
|
84
|
+
The `lteq` predicate returns all records where a field is less than *or equal to* a given value:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
>> User.ransack(age_lteq: 25).result.to_sql
|
88
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."age" <= 25)
|
89
|
+
```
|
90
|
+
|
91
|
+
**Opposite: `gt` (greater than)**
|
92
|
+
|
93
|
+
## in
|
94
|
+
|
95
|
+
The `in` predicate returns all records where a field is within a specified list:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
>> User.ransack(age_in: 20..25).result.to_sql
|
99
|
+
=> SELECT "users".* FROM "users" WHERE "users"."age" IN (20, 21, 22, 23, 24, 25)
|
100
|
+
```
|
101
|
+
|
102
|
+
It can also take an array:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
>> User.ransack(age_in: [20, 21, 22, 23, 24, 25]).result.to_sql
|
106
|
+
=> SELECT "users".* FROM "users" WHERE "users"."age" IN (20, 21, 22, 23, 24, 25)
|
107
|
+
```
|
108
|
+
|
109
|
+
**Opposite: `not_in`**
|
110
|
+
|
111
|
+
## cont
|
112
|
+
|
113
|
+
The `cont` predicate returns all records where a field contains a given value:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
>> User.ransack(first_name_cont: 'Rya').result.to_sql
|
117
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Rya%')
|
118
|
+
```
|
119
|
+
|
120
|
+
**Opposite: `not_cont`**
|
121
|
+
|
122
|
+
## cont_any (contains any)
|
123
|
+
|
124
|
+
The `cont_any` predicate returns all records where a field contains any of the given values:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
>> User.ransack(first_name_cont_any: %w(Rya Lis)).result.to_sql
|
128
|
+
=> SELECT "users".* FROM "users" WHERE (("users"."first_name" LIKE '%Rya%' OR "users"."first_name" LIKE '%Lis%'))
|
129
|
+
```
|
130
|
+
|
131
|
+
**Opposite: `not_cont_any`**
|
132
|
+
|
133
|
+
|
134
|
+
## cont_all (contains all)
|
135
|
+
|
136
|
+
The `cont_all` predicate returns all records where a field contains all of the given values:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
>> User.ransack(city_cont_all: %w(Grand Rapids)).result.to_sql
|
140
|
+
=> SELECT "users".* FROM "users" WHERE (("users"."city" LIKE '%Grand%' AND "users"."city" LIKE '%Rapids%'))
|
141
|
+
```
|
142
|
+
|
143
|
+
**Opposite: `not_cont_all`**
|
144
|
+
|
145
|
+
|
146
|
+
## i_cont
|
147
|
+
|
148
|
+
The `i_cont` case-insensitive predicate returns all records where a field contains a given value and ignores case:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
>> User.ransack(first_name_i_cont: 'Rya').result.to_sql
|
152
|
+
=> SELECT "users".* FROM "users" WHERE (LOWER("users"."first_name") LIKE '%rya%')
|
153
|
+
```
|
154
|
+
|
155
|
+
**Opposite: `not_i_cont`**
|
156
|
+
|
157
|
+
## i_cont_any
|
158
|
+
|
159
|
+
The `i_cont_any` case-insensitive predicate returns all records where a field contains any of the given values and ignores case:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
>> User.ransack(first_name_i_cont_any: %w(Rya Lis)).result.to_sql
|
163
|
+
=> SELECT "users".* FROM "users" WHERE ((LOWER("users"."first_name") LIKE '%rya%' OR LOWER("users"."first_name") LIKE '%lis%'))
|
164
|
+
```
|
165
|
+
|
166
|
+
**Opposite: `not_i_cont_any`**
|
167
|
+
|
168
|
+
|
169
|
+
## i_cont_all
|
170
|
+
|
171
|
+
The `i_cont_all` case-insensitive predicate returns all records where a field contains all of the given values and ignores case:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
>> User.ransack(city_i_cont_all: %w(Grand Rapids)).result.to_sql
|
175
|
+
=> SELECT "users".* FROM "users" WHERE ((LOWER("users"."city") LIKE '%grand%' AND LOWER("users"."city") LIKE '%rapids%'))
|
176
|
+
```
|
177
|
+
|
178
|
+
**Opposite: `not_i_cont_all`**
|
179
|
+
|
180
|
+
## start (starts with)
|
181
|
+
|
182
|
+
The `start` predicate returns all records where a field begins with a given value:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
>> User.ransack(first_name_start: 'Rya').result.to_sql
|
186
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE 'Rya%')
|
187
|
+
```
|
188
|
+
|
189
|
+
**Opposite: `not_start`**
|
190
|
+
|
191
|
+
## end (ends with)
|
192
|
+
|
193
|
+
The `end` predicate returns all records where a field ends with a given value:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
>> User.ransack(first_name_end: 'yan').result.to_sql
|
197
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%yan')
|
198
|
+
```
|
199
|
+
|
200
|
+
**Opposite: `not_end`**
|
201
|
+
|
202
|
+
## true
|
203
|
+
|
204
|
+
The `true` predicate returns all records where a field is true. The '1' indicates that
|
205
|
+
to Ransack that you indeed want to check the truthiness of this field. The other truthy
|
206
|
+
values are 'true', 'TRUE', 't' or 'T'.
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
>> User.ransack(awesome_true: '1').result.to_sql
|
210
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."awesome" = 't')
|
211
|
+
```
|
212
|
+
|
213
|
+
*Note: different database systems use different values to represent truth. In the above
|
214
|
+
example, we are using SQLite3.*
|
215
|
+
|
216
|
+
**Opposite: `not_true`**
|
217
|
+
|
218
|
+
## false
|
219
|
+
|
220
|
+
The `false` predicate returns all records where a field is false.
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
>> User.ransack(awesome_false: '1').result.to_sql
|
224
|
+
=> SELECT "users".* FROM "users" WHERE ("users"."awesome" = 'f')
|
225
|
+
```
|
226
|
+
|
227
|
+
**Opposite: `not_false`**
|
228
|
+
|
229
|
+
*Note: the `false` predicate may be considered the opposite of the `true` predicate if the field does not contain `null` values. Otherwise, use `not_false`.*
|
230
|
+
|
231
|
+
## present
|
232
|
+
|
233
|
+
The `present` predicate returns all records where a field is present (not null and not a
|
234
|
+
blank string).
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
>> User.ransack(first_name_present: '1').result.to_sql
|
238
|
+
=> SELECT "users".* FROM "users" WHERE (("users"."first_name" IS NOT NULL AND "users"."first_name" != ''))
|
239
|
+
```
|
240
|
+
|
241
|
+
**Opposite: `blank`**
|
242
|
+
|
243
|
+
## null
|
244
|
+
|
245
|
+
The `null` predicate returns all records where a field is null:
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
>> User.ransack(first_name_null: 1).result.to_sql
|
249
|
+
=> SELECT "users".* FROM "users" WHERE "users"."first_name" IS NULL
|
250
|
+
```
|
251
|
+
|
252
|
+
**Opposite: `not_null`**
|
253
|
+
|
254
|
+
# URL parameter structure
|
255
|
+
|
256
|
+
The search parameters are passed to ransack as a hash. The URL representation of this hash uses the bracket notation: ```hash_name[key]=value```. The hash_name is the parameter which is defined in the controller, for instance ```q```. The key is the attribute and search predicate compound, for instance ```first_name_cont```, the value is the search parameter. When searching without using the search form helpers this URL structure needs to be created manually.
|
257
|
+
|
258
|
+
For example, the URL layout for searching and sorting users could looks like this:
|
259
|
+
|
260
|
+
```
|
261
|
+
/users.json?q[first_name_cont]=pete&q[last_name_cont]=jack&q[s]=created_at+desc
|
262
|
+
```
|
263
|
+
|
264
|
+
_Note that the sorting parameter ```s``` is nested within the ```q``` hash._
|
265
|
+
|
266
|
+
When using JavaScript to create such a URL, a matching jQuery request could look like this:
|
267
|
+
|
268
|
+
```javascript
|
269
|
+
$.ajax({
|
270
|
+
url: "/users.json",
|
271
|
+
data: {
|
272
|
+
q: {
|
273
|
+
first_name_cont: "pete",
|
274
|
+
last_name_cont: "jack",
|
275
|
+
s: "created_at desc"
|
276
|
+
}
|
277
|
+
},
|
278
|
+
success: function (data){
|
279
|
+
console.log(data);
|
280
|
+
}
|
281
|
+
});
|
282
|
+
```
|
@@ -0,0 +1,70 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 1
|
3
|
+
title: Associations
|
4
|
+
---
|
5
|
+
|
6
|
+
### Associations
|
7
|
+
|
8
|
+
You can easily use Ransack to search for objects in `has_many` and `belongs_to`
|
9
|
+
associations.
|
10
|
+
|
11
|
+
Given these associations...
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class Employee < ActiveRecord::Base
|
15
|
+
belongs_to :supervisor
|
16
|
+
|
17
|
+
# has attributes first_name:string and last_name:string
|
18
|
+
end
|
19
|
+
|
20
|
+
class Department < ActiveRecord::Base
|
21
|
+
has_many :supervisors
|
22
|
+
|
23
|
+
# has attribute title:string
|
24
|
+
end
|
25
|
+
|
26
|
+
class Supervisor < ActiveRecord::Base
|
27
|
+
belongs_to :department
|
28
|
+
has_many :employees
|
29
|
+
|
30
|
+
# has attribute last_name:string
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
... and a controller...
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class SupervisorsController < ApplicationController
|
38
|
+
def index
|
39
|
+
@q = Supervisor.ransack(params[:q])
|
40
|
+
@supervisors = @q.result.includes(:department, :employees)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
... you might set up your form like this...
|
46
|
+
|
47
|
+
```erb
|
48
|
+
<%= search_form_for @q do |f| %>
|
49
|
+
<%= f.label :last_name_cont %>
|
50
|
+
<%= f.search_field :last_name_cont %>
|
51
|
+
|
52
|
+
<%= f.label :department_title_cont %>
|
53
|
+
<%= f.search_field :department_title_cont %>
|
54
|
+
|
55
|
+
<%= f.label :employees_first_name_or_employees_last_name_cont %>
|
56
|
+
<%= f.search_field :employees_first_name_or_employees_last_name_cont %>
|
57
|
+
|
58
|
+
<%= f.submit "search" %>
|
59
|
+
<% end %>
|
60
|
+
...
|
61
|
+
<%= content_tag :table do %>
|
62
|
+
<%= content_tag :th, sort_link(@q, :last_name) %>
|
63
|
+
<%= content_tag :th, sort_link(@q, :department_title) %>
|
64
|
+
<%= content_tag :th, sort_link(@q, :employees_last_name) %>
|
65
|
+
<% end %>
|
66
|
+
```
|
67
|
+
|
68
|
+
If you have trouble sorting on associations, try using an SQL string with the
|
69
|
+
pluralized table (`'departments.title'`,`'employees.last_name'`) instead of the
|
70
|
+
symbolized association (`:department_title)`, `:employees_last_name`).
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 1
|
3
|
+
title: Custom predicates
|
4
|
+
---
|
5
|
+
|
6
|
+
If you'd like to add your own custom Ransack predicates:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# config/initializers/ransack.rb
|
10
|
+
|
11
|
+
Ransack.configure do |config|
|
12
|
+
config.add_predicate 'equals_diddly', # Name your predicate
|
13
|
+
# What non-compound ARel predicate will it use? (eq, matches, etc)
|
14
|
+
arel_predicate: 'eq',
|
15
|
+
# Format incoming values as you see fit. (Default: Don't do formatting)
|
16
|
+
formatter: proc { |v| "#{v}-diddly" },
|
17
|
+
# Validate a value. An "invalid" value won't be used in a search.
|
18
|
+
# Below is default.
|
19
|
+
validator: proc { |v| v.present? },
|
20
|
+
# Should compounds be created? Will use the compound (any/all) version
|
21
|
+
# of the arel_predicate to create a corresponding any/all version of
|
22
|
+
# your predicate. (Default: true)
|
23
|
+
compounds: true,
|
24
|
+
# Force a specific column type for type-casting of supplied values.
|
25
|
+
# (Default: use type from DB column)
|
26
|
+
type: :string,
|
27
|
+
# Use LOWER(column on database).
|
28
|
+
# (Default: false)
|
29
|
+
case_insensitive: true
|
30
|
+
end
|
31
|
+
```
|
32
|
+
You can check all Arel predicates [here](https://github.com/rails/rails/blob/main/activerecord/lib/arel/predications.rb).
|
33
|
+
|
34
|
+
If Arel does not have the predicate you are looking for, consider monkey patching it:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# config/initializers/ransack.rb
|
38
|
+
|
39
|
+
module Arel
|
40
|
+
module Predications
|
41
|
+
def gteq_or_null(other)
|
42
|
+
left = gteq(other)
|
43
|
+
right = eq(nil)
|
44
|
+
left.or(right)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Ransack.configure do |config|
|
50
|
+
config.add_predicate 'gteq_or_null', arel_predicate: 'gteq_or_null'
|
51
|
+
end
|
52
|
+
```
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 11
|
3
|
+
title: Documentation
|
4
|
+
---
|
5
|
+
|
6
|
+
Ransack uses [Docusaurus](https://docusaurus.io/) for documentation. To contribute to the docs simply use the "Edit this page" link from any page to directly edit, or else pull the repo and edit locally.
|
7
|
+
|
8
|
+
### Local Development
|
9
|
+
|
10
|
+
```
|
11
|
+
cd docs
|
12
|
+
yarn start
|
13
|
+
```
|
14
|
+
|
15
|
+
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
16
|
+
|
17
|
+
### Build
|
18
|
+
|
19
|
+
```
|
20
|
+
yarn build
|
21
|
+
```
|
22
|
+
|
23
|
+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
24
|
+
|
25
|
+
### Deployment
|
26
|
+
|
27
|
+
Using SSH:
|
28
|
+
|
29
|
+
```
|
30
|
+
USE_SSH=true yarn deploy
|
31
|
+
```
|
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 2
|
3
|
+
title: CSV Export
|
4
|
+
---
|
5
|
+
|
6
|
+
Exporting to CSV
|
7
|
+
|
8
|
+
Example downloading a csv file preserving ransack search, based on [this gist](https://gist.github.com/pama/adff25ed1f4b796ce088ea362a08e1c5)
|
9
|
+
|
10
|
+
```jsx title='index.html.erb'
|
11
|
+
<h1>Users</h1>
|
12
|
+
|
13
|
+
<%= search_form_for @q, url: dashboard_index_path do |f| %>
|
14
|
+
<%= f.label :name_cont %>
|
15
|
+
<%= f.search_field :name_cont %>
|
16
|
+
|
17
|
+
<%= f.submit %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<ul>
|
21
|
+
<% @users.each do |user| %>
|
22
|
+
<li><%= user.name %> [<%= user.devices.map {|device| device.name }.join(', ') %>]</li>
|
23
|
+
<% end %>
|
24
|
+
</ul>
|
25
|
+
|
26
|
+
<% if params[:q] %>
|
27
|
+
<%= link_to 'Export 1', dashboard_index_path({name: params[:q][:name_cont]}.merge({format: :csv})) %>
|
28
|
+
<% else %>
|
29
|
+
<%= link_to 'Export 2', dashboard_index_path(format: 'csv') %>
|
30
|
+
<% end %>
|
31
|
+
```
|
32
|
+
|
33
|
+
```jsx title='user.rb'
|
34
|
+
require 'csv'
|
35
|
+
|
36
|
+
class User < ApplicationRecord
|
37
|
+
has_many :devices
|
38
|
+
|
39
|
+
def self.get_csv(users)
|
40
|
+
CSV.generate do |csv|
|
41
|
+
csv << ["Name", "Devices"]
|
42
|
+
|
43
|
+
users.each do |user|
|
44
|
+
csv << [user.name, user.devices.map{|device| device.name}.join(', ')]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
@@ -0,0 +1,57 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 9
|
3
|
+
title: External resources
|
4
|
+
---
|
5
|
+
|
6
|
+
There is a plethora of material on Ransack around the internet. We've collected some here for your convenience.
|
7
|
+
|
8
|
+
Do you want to have a blog post or other content on Ransack highlighted? Please just edit the page, add your content and a Pull Request will be sent to Ransack maintainers for approval.
|
9
|
+
|
10
|
+
# Screencasts
|
11
|
+
|
12
|
+
- [DriftingRuby: Ransack Search and Hotwire](https://www.driftingruby.com/episodes/ransack-search-and-hotwire)
|
13
|
+
- [GoRails: Forum Series Part 6: Search with Ransack](https://gorails.com/episodes/forum-search-with-ransack)
|
14
|
+
- [Railscast 370 - Ransack](http://railscasts.com/episodes/370-ransack)
|
15
|
+
- [Search And Sort Ransack Associations With The Rails Ransack Gem | Ruby On Rails 6 Ransack Tutorial](https://www.youtube.com/watch?v=rtg-5EXwpbg)
|
16
|
+
|
17
|
+
|
18
|
+
# Gems
|
19
|
+
|
20
|
+
- [ActiveAdmin](https://activeadmin.info/) The Administration Framework for Rails **_uses Ransack internally_**
|
21
|
+
- [Ransack Memory](https://github.com/richardrails/ransack_memory) Automatically save and load Ransack's filtered params into the Rail's session
|
22
|
+
- [Mobility Ransack](https://github.com/shioyama/mobility-ransack) Search attributes translated by Mobility with Ransack.
|
23
|
+
- [Ransack UI](https://github.com/ndbroadbent/ransack_ui) Framework for building a search UI with Ransack **_seems abandoned_**
|
24
|
+
|
25
|
+
# Blogs
|
26
|
+
|
27
|
+
- [Search And Sort In Ruby On Rails 6 With The Ransack Gem](https://deanin.com/blog/ransack/)
|
28
|
+
- [Implement Ransack Gem in Ruby on Rails](https://www.botreetechnologies.com/blog/implementing-advanced-search-in-ruby-on-rails-with-ransack/)
|
29
|
+
- [Searching and Sorting with Ransack](https://jaspercurry.medium.com/searching-and-sorting-on-rails-with-ransack-560e862e650a)
|
30
|
+
- [How to Build Your Own ActiveAdmin Filters with Ransack](https://www.viget.com/articles/how-to-build-your-own-filters-with-ransack/)
|
31
|
+
- [Avoid Ransack's N+1 Pitfall!](https://dev.to/husteadrobert/avoid-ransacks-n1-pitfall-33of)
|
32
|
+
- [Filter and paging with Kaminari](https://gist.github.com/MyklClason/e4dc96fd0e009b7b3a9c84ddbb1e11d2)
|
33
|
+
- [Pagination for Ransack Forms](https://nicholaide.github.io/ransack/2016/11/26/ransack-pagination.html)
|
34
|
+
- [AJAX Search, Sort, Paginate with Ransack and Kaminari](https://techbrownbags.wordpress.com/2014/01/17/rails-ajax-search-sort-paginate-with-ransack-kaminari/)
|
35
|
+
- [Searching with Ransack in Ruby on Rails](http://blog.magmalabs.io/2019/03/12/searching-with-ransack-in-ruby-on-rails.html)
|
36
|
+
- [Role scopes with gem Ransack](https://blog.corsego.com/rolify-scopes)
|
37
|
+
- [Searching and Sorting with Ransack](https://www.mintbit.com/blog/searching-and-sorting-with-ransack)
|
38
|
+
- [Using custom scopes with Ransack gem in Rails](https://profilehunt.net/blog/using-custom-scopes-with-ransack-in-rails)
|
39
|
+
- [Query Date Range With Ransack](https://lingceng.github.io/blog/2015/12/28/query-date-range-with-ransack/)
|
40
|
+
- [ransack vs searchkick: Building a search feature in Rails](https://www.cookieshq.co.uk/posts/ransack-vs-searchkick-building-a-search-feature-in-rails)
|
41
|
+
- [Using ransack and delegate in Rails](https://huangwenwei.com/blogs/using-ransack-and-delegate-in-rails)
|
42
|
+
- [Using Ransack as a Search Engine](https://medium.com/@jelaniwoods/using-ransack-as-a-search-engine-92e002a68da)
|
43
|
+
- [Advanced Search with Ransack](https://www.sitepoint.com/advanced-search-ransack/)
|
44
|
+
- [Sort a table of records in Rails with Ransack](https://alankydd.wordpress.com/2012/03/12/sort-a-table-of-records-in-rails-with-ransack/)
|
45
|
+
- [Ransack: Search with Multiple Checkboxes (Rails)](https://iamjosh.wordpress.com/2014/03/07/ransack-search-with-multiple-checkboxes/)
|
46
|
+
- [Rails : Ransack : Sorting data by ratings](https://cbabhusal.wordpress.com/2017/01/03/rails-ransack-sorting-data-by-ratings/)
|
47
|
+
- [Setting Up Rails 5 API Only App with ActiveAdmin enabled](https://rrott.com/blog/ror/rails-5-api-with-activeadmin-integration/)
|
48
|
+
- [Ransack, the library formerly known as MetaSearch 2.0](https://ernie.io/2011/04/01/ransack-the-library-formerly-known-as-metasearch-2-0/) **_some Ransack history_**
|
49
|
+
|
50
|
+
## In French
|
51
|
+
|
52
|
+
- [Faciliter les recherches avec Ransack](https://www.synbioz.com/blog/tech/faciliter-les-recherches-avec-ransack)
|
53
|
+
|
54
|
+
## In Vietnamese
|
55
|
+
|
56
|
+
- [Ransack - công cụ tuyệt vời giúp tìm kiếm và sắp xếp dữ liệu đơn giản hơn
|
57
|
+
](https://nddblog.com/posts/ransack-cong-cu-tuyet-voi-giup-tim-kiem-va-sap-xep-du-lieu-don-gian-hon)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 4
|
3
|
+
title: Form customisation
|
4
|
+
---
|
5
|
+
|
6
|
+
Predicate and attribute labels in forms may be specified with I18n in a translation file (see the locale files in [Ransack::Locale](https://github.com/activerecord-hackery/ransack/activerecord-hackery/ransack/tree/master/lib/ransack/locale) for more examples):
|
7
|
+
|
8
|
+
```yml
|
9
|
+
# locales/en.yml
|
10
|
+
en:
|
11
|
+
ransack:
|
12
|
+
asc: ascending
|
13
|
+
desc: descending
|
14
|
+
predicates:
|
15
|
+
cont: contains
|
16
|
+
not_cont: not contains
|
17
|
+
start: starts with
|
18
|
+
end: ends with
|
19
|
+
gt: greater than
|
20
|
+
lt: less than
|
21
|
+
attributes:
|
22
|
+
person:
|
23
|
+
name: Full Name
|
24
|
+
article:
|
25
|
+
title: Article Title
|
26
|
+
body: Main Content
|
27
|
+
```
|
28
|
+
The names of attribute fields may also be changed globally or under activerecord:
|
29
|
+
|
30
|
+
```yml
|
31
|
+
# locales/en.yml
|
32
|
+
en:
|
33
|
+
attributes:
|
34
|
+
model_name:
|
35
|
+
model_field1: field name1
|
36
|
+
model_field2: field name2
|
37
|
+
activerecord:
|
38
|
+
attributes:
|
39
|
+
namespace/article:
|
40
|
+
title: AR Namespaced Title
|
41
|
+
namespace_article:
|
42
|
+
title: Old Ransack Namespaced Title
|
43
|
+
```
|
44
|
+
|
45
|
+
To limit the predicates in the `predicate_select` form helper in a view template, pass an array of permitted predicates with `only`:
|
46
|
+
|
47
|
+
```erb
|
48
|
+
<%= f.predicate_select only: %i(cont not_cont eq not_eq blank null) %>
|
49
|
+
```
|
50
|
+
|
51
|
+
Compound predicates (`_any` & `_all`) may be removed by passing the option `compounds: false`.
|
52
|
+
|
53
|
+
```erb
|
54
|
+
<%= f.predicate_select compounds: false %>
|
55
|
+
```
|
56
|
+
|
57
|
+
Searchable attributes versus non-searchable ones may be specified as follows:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
def self.ransackable_attributes(auth_object = nil)
|
61
|
+
%w(searchable_attribute_1 searchable_attribute_2 ...) + _ransackers.keys
|
62
|
+
end
|
63
|
+
```
|
@@ -0,0 +1,53 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 3
|
3
|
+
title: i18n
|
4
|
+
---
|
5
|
+
|
6
|
+
# i18n and Ransack
|
7
|
+
|
8
|
+
Ransack translation files are available in
|
9
|
+
[Ransack::Locale](https://github.com/activerecord-hackery/ransack/lib/ransack/locale). You may also be interested in one of the
|
10
|
+
many translations for Ransack available at
|
11
|
+
http://www.localeapp.com/projects/2999.
|
12
|
+
|
13
|
+
Predicate and attribute translations in forms may be specified as follows (see
|
14
|
+
the translation files in [Ransack::Locale](https://github.com/activerecord-hackery/ransack/lib/ransack/locale) for more examples):
|
15
|
+
|
16
|
+
locales/en.yml:
|
17
|
+
```yml
|
18
|
+
en:
|
19
|
+
ransack:
|
20
|
+
asc: ascending
|
21
|
+
desc: descending
|
22
|
+
predicates:
|
23
|
+
cont: contains
|
24
|
+
not_cont: not contains
|
25
|
+
start: starts with
|
26
|
+
end: ends with
|
27
|
+
gt: greater than
|
28
|
+
lt: less than
|
29
|
+
models:
|
30
|
+
person: Passanger
|
31
|
+
attributes:
|
32
|
+
person:
|
33
|
+
name: Full Name
|
34
|
+
article:
|
35
|
+
title: Article Title
|
36
|
+
body: Main Content
|
37
|
+
```
|
38
|
+
|
39
|
+
Attribute names may also be changed globally, or under `activerecord`:
|
40
|
+
|
41
|
+
```yml
|
42
|
+
en:
|
43
|
+
attributes:
|
44
|
+
model_name:
|
45
|
+
model_field1: field name1
|
46
|
+
model_field2: field name2
|
47
|
+
activerecord:
|
48
|
+
attributes:
|
49
|
+
namespace/article:
|
50
|
+
title: AR Namespaced Title
|
51
|
+
namespace_article:
|
52
|
+
title: Old Ransack Namespaced Title
|
53
|
+
```
|
File without changes
|