ransack 3.2.1 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/codeql.yml +72 -0
- data/.github/workflows/cronjob.yml +6 -9
- data/.github/workflows/deploy.yml +1 -1
- data/.github/workflows/rubocop.yml +2 -2
- data/.github/workflows/test-deploy.yml +1 -1
- data/.github/workflows/test.yml +23 -22
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +86 -0
- data/CONTRIBUTING.md +40 -21
- data/Gemfile +10 -10
- data/README.md +4 -9
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +1 -1
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +5 -1
- data/docs/docs/getting-started/advanced-mode.md +1 -1
- data/docs/docs/getting-started/search-matches.md +1 -1
- data/docs/docs/getting-started/simple-mode.md +6 -2
- data/docs/docs/getting-started/sorting.md +45 -53
- data/docs/docs/going-further/acts-as-taggable-on.md +4 -4
- data/docs/docs/going-further/form-customisation.md +1 -1
- data/docs/docs/going-further/i18n.md +3 -3
- data/docs/docs/going-further/other-notes.md +2 -2
- data/docs/docs/going-further/polymorphic-search.md +6 -0
- data/docs/docs/going-further/saving-queries.md +1 -1
- data/docs/docs/going-further/searching-postgres.md +1 -1
- data/docs/package.json +7 -3
- data/docs/yarn.lock +2371 -1928
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +14 -4
- data/lib/ransack/adapters/active_record/base.rb +78 -7
- data/lib/ransack/adapters/active_record/context.rb +2 -1
- data/lib/ransack/configuration.rb +25 -12
- data/lib/ransack/constants.rb +125 -0
- data/lib/ransack/context.rb +34 -5
- data/lib/ransack/helpers/form_builder.rb +3 -3
- data/lib/ransack/helpers/form_helper.rb +3 -2
- data/lib/ransack/nodes/attribute.rb +2 -2
- data/lib/ransack/nodes/condition.rb +80 -7
- data/lib/ransack/nodes/grouping.rb +3 -3
- data/lib/ransack/nodes/node.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +1 -1
- data/lib/ransack/ransacker.rb +1 -1
- data/lib/ransack/search.rb +9 -4
- data/lib/ransack/translate.rb +2 -2
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +38 -2
- data/lib/ransack.rb +3 -6
- data/ransack.gemspec +1 -1
- data/spec/ransack/adapters/active_record/base_spec.rb +89 -0
- data/spec/ransack/configuration_spec.rb +9 -9
- data/spec/ransack/helpers/form_builder_spec.rb +8 -8
- data/spec/ransack/helpers/form_helper_spec.rb +36 -2
- data/spec/ransack/nodes/condition_spec.rb +24 -0
- data/spec/ransack/predicate_spec.rb +36 -1
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/support/schema.rb +55 -10
- metadata +6 -13
- data/lib/polyamorous.rb +0 -1
- data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -128
- data/lib/ransack/adapters/active_record/ransack/context.rb +0 -56
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +0 -61
- data/lib/ransack/adapters/active_record/ransack/translate.rb +0 -8
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +0 -47
- data/lib/ransack/adapters.rb +0 -64
- data/lib/ransack/nodes.rb +0 -8
- /data/lib/ransack/{adapters/active_record.rb → active_record.rb} +0 -0
@@ -27,6 +27,10 @@ def index
|
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
+
:::caution
|
31
|
+
By default, searching and sorting are authorized on any column of your model. See [Authorization (allowlisting/denylisting)](/going-further/other-notes.md#authorization-allowlistingdenylisting) on how to prevent this.
|
32
|
+
:::
|
33
|
+
|
30
34
|
### Default search options
|
31
35
|
|
32
36
|
#### Search parameter
|
@@ -50,7 +54,7 @@ This may be disabled by setting the `strip_whitespace` option in a Ransack initi
|
|
50
54
|
|
51
55
|
```ruby
|
52
56
|
Ransack.configure do |c|
|
53
|
-
# Change whitespace stripping
|
57
|
+
# Change whitespace stripping behavior.
|
54
58
|
# Default is true
|
55
59
|
c.strip_whitespace = false
|
56
60
|
end
|
@@ -60,7 +64,7 @@ end
|
|
60
64
|
|
61
65
|
The two primary Ransack view helpers are `search_form_for` and `sort_link`,
|
62
66
|
which are defined in
|
63
|
-
[Ransack::Helpers::FormHelper](https://github.com/activerecord-hackery/ransack/lib/ransack/helpers/form_helper.rb).
|
67
|
+
[Ransack::Helpers::FormHelper](https://github.com/activerecord-hackery/ransack/blob/main/lib/ransack/helpers/form_helper.rb).
|
64
68
|
|
65
69
|
### Form helper
|
66
70
|
|
@@ -10,70 +10,62 @@ title: Sorting
|
|
10
10
|
You can add a form to capture sorting and filtering options together.
|
11
11
|
|
12
12
|
```erb
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
<
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
<div class="form-group">
|
39
|
-
<%= f.label :readability_gteq, t('Readability') %> >=
|
40
|
-
<%= f.search_field :readability_gteq %>
|
41
|
-
</div>
|
42
|
-
|
43
|
-
<div class="form-group">
|
44
|
-
<i><%= @articles.total_count %> articles</i>
|
45
|
-
</div>
|
46
|
-
|
47
|
-
<div class="form-group">
|
48
|
-
<hr/>
|
49
|
-
<div class="filters-header-content">
|
50
|
-
<%= link_to request.path, class: 'form-link' do %>
|
51
|
-
<i class="far fa-undo icon-l"></i><%= t('Clear_all') %>
|
52
|
-
<% end %>
|
53
|
-
|
54
|
-
<%= f.submit t('Filter'), class: 'btn btn-primary' %>
|
55
|
-
</div>
|
56
|
-
</div>
|
13
|
+
# app/views/posts/index.html.erb
|
14
|
+
|
15
|
+
<%= search_form_for @q do |f| %>
|
16
|
+
<%= f.label :title_cont %>
|
17
|
+
<%= f.search_field :title_cont %>
|
18
|
+
|
19
|
+
<%= f.submit "Search" %>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<table>
|
23
|
+
<thead>
|
24
|
+
<tr>
|
25
|
+
<th><%= sort_link(@q, :title, "Title") %></th>
|
26
|
+
<th><%= sort_link(@q, :category, "Category") %></th>
|
27
|
+
<th><%= sort_link(@q, :created_at, "Created at") %></th>
|
28
|
+
</tr>
|
29
|
+
</thead>
|
30
|
+
|
31
|
+
<tbody>
|
32
|
+
<% @posts.each do |post| %>
|
33
|
+
<tr>
|
34
|
+
<td><%= post.title %></td>
|
35
|
+
<td><%= post.category %></td>
|
36
|
+
<td><%= post.created_at.to_s(:long) %></td>
|
37
|
+
</tr>
|
57
38
|
<% end %>
|
58
|
-
</
|
59
|
-
</
|
39
|
+
</tbody>
|
40
|
+
</table>
|
60
41
|
```
|
61
42
|
|
62
|
-
|
63
43
|
## Sorting in the Controller
|
64
44
|
|
65
45
|
To specify a default search sort field + order in the controller `index`:
|
66
46
|
|
67
47
|
```ruby
|
68
|
-
|
69
|
-
|
70
|
-
|
48
|
+
# app/controllers/posts_controller.rb
|
49
|
+
class PostsController < ActionController::Base
|
50
|
+
def index
|
51
|
+
@q = Post.ransack(params[:q])
|
52
|
+
@q.sorts = 'title asc' if @q.sorts.empty?
|
53
|
+
|
54
|
+
@posts = @q.result(distinct: true)
|
55
|
+
end
|
56
|
+
end
|
71
57
|
```
|
72
58
|
|
73
59
|
Multiple sorts can be set by:
|
74
60
|
|
75
61
|
```ruby
|
76
|
-
|
77
|
-
|
78
|
-
|
62
|
+
# app/controllers/posts_controller.rb
|
63
|
+
class PostsController < ActionController::Base
|
64
|
+
def index
|
65
|
+
@q = Post.ransack(params[:q])
|
66
|
+
@q.sorts = ['title asc', 'created_at desc'] if @q.sorts.empty?
|
67
|
+
|
68
|
+
@posts = @q.result(distinct: true)
|
69
|
+
end
|
70
|
+
end
|
79
71
|
```
|
@@ -67,24 +67,24 @@ When you're writing a `Ransack` search form, you can choose any of the following
|
|
67
67
|
|
68
68
|
### Option A - Match keys exactly
|
69
69
|
|
70
|
-
Option `
|
70
|
+
Option `A` will match keys exactly. This is the solution to choose if you want to distinguish 'Home' from 'Homework': searching for 'Home' will return just the `Task` with id 1. It also allows searching for more than one tag at once (comma separated):
|
71
71
|
- `Home, Personal` will return task 1
|
72
72
|
- `Home, Homework` will return task 1 and 2
|
73
73
|
|
74
74
|
### Option B - match key combinations
|
75
75
|
|
76
|
-
Option `
|
76
|
+
Option `B` will match all keys exactly. This is the solution if you wanna search for specific combinations of tags:
|
77
77
|
- `Home` will return nothing, as there is no Task with just the `Home` tag
|
78
78
|
- `Home, Personal` will return task 1
|
79
79
|
|
80
80
|
### Option C - match substrings
|
81
81
|
|
82
|
-
Option `
|
82
|
+
Option `C` is used to match substrings. This is useful when you don't care for the exact tag, but only for part of it:
|
83
83
|
- `Home` will return task 1 and 2 (`/Home/` matches both `"Home"` and `"Homework"`)
|
84
84
|
|
85
85
|
### Option D - select from a list of tags
|
86
86
|
|
87
|
-
In Option D we allow the user to select a list of valid tags and then search
|
87
|
+
In Option `D` we allow the user to select a list of valid tags and then search against them. We use the plural name here.
|
88
88
|
|
89
89
|
```erb
|
90
90
|
<div class='form-group'>
|
@@ -3,7 +3,7 @@ sidebar_position: 4
|
|
3
3
|
title: Form customisation
|
4
4
|
---
|
5
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/
|
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/tree/main/lib/ransack/locale) for more examples):
|
7
7
|
|
8
8
|
```yml
|
9
9
|
# locales/en.yml
|
@@ -6,12 +6,12 @@ title: i18n
|
|
6
6
|
# i18n and Ransack
|
7
7
|
|
8
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
|
9
|
+
[Ransack::Locale](https://github.com/activerecord-hackery/ransack/tree/main/lib/ransack/locale). You may also be interested in one of the
|
10
10
|
many translations for Ransack available at
|
11
11
|
http://www.localeapp.com/projects/2999.
|
12
12
|
|
13
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):
|
14
|
+
the translation files in [Ransack::Locale](https://github.com/activerecord-hackery/ransack/tree/main/lib/ransack/locale) for more examples):
|
15
15
|
|
16
16
|
locales/en.yml:
|
17
17
|
```yml
|
@@ -27,7 +27,7 @@ en:
|
|
27
27
|
gt: greater than
|
28
28
|
lt: less than
|
29
29
|
models:
|
30
|
-
person:
|
30
|
+
person: Passenger
|
31
31
|
attributes:
|
32
32
|
person:
|
33
33
|
name: Full Name
|
@@ -182,7 +182,7 @@ for an `auth_object` key in the options hash which can be used by your own
|
|
182
182
|
overridden methods.
|
183
183
|
|
184
184
|
Here is an example that puts all this together, adapted from
|
185
|
-
[this blog post by Ernie Miller](
|
185
|
+
[this blog post by Ernie Miller](https://ernie.io/2012/05/11/why-your-ruby-class-macros-might-suck-mine-did/).
|
186
186
|
In an `Article` model, add the following `ransackable_attributes` class method
|
187
187
|
(preferably private):
|
188
188
|
|
@@ -354,7 +354,7 @@ argument are not easily usable yet, because the array currently needs to be
|
|
354
354
|
wrapped in an array to function (see
|
355
355
|
[this issue](https://github.com/activerecord-hackery/ransack/issues/404)),
|
356
356
|
which is not compatible with Ransack form helpers. For this use case, it may be
|
357
|
-
better for now to use [ransackers](https://
|
357
|
+
better for now to use [ransackers](https://activerecord-hackery.github.io/ransack/going-further/ransackers) instead,
|
358
358
|
where feasible. Pull requests with solutions and tests are welcome!
|
359
359
|
|
360
360
|
### Grouping queries by OR instead of AND
|
@@ -38,3 +38,9 @@ Location.ransack(locatable_of_House_type_number_eq: 100).result
|
|
38
38
|
```
|
39
39
|
|
40
40
|
note the `_of_House_type_` added to the search key. This allows Ransack to correctly specify the table names in SQL join queries.
|
41
|
+
|
42
|
+
For namespaced models you should use a quoted string containing the standard Ruby module notation
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Location.ransack('locatable_of_Residences::House_type_number_eq' => 100).result
|
46
|
+
```
|
@@ -72,7 +72,7 @@ class ApplicationController < ActionController::Base
|
|
72
72
|
end
|
73
73
|
|
74
74
|
protected
|
75
|
-
# GENERATE A GENERIC SESSION KEY BASED ON
|
75
|
+
# GENERATE A GENERIC SESSION KEY BASED ON THE CONTROLLER NAME
|
76
76
|
def search_key
|
77
77
|
"#{controller_name}_search".to_sym
|
78
78
|
end
|
@@ -13,7 +13,7 @@ See [this issue](https://github.com/activerecord-hackery/ransack/issues/321) for
|
|
13
13
|
|
14
14
|
### Using a fixed key
|
15
15
|
|
16
|
-
See here for searching on a fixed key in a JSONB column: https://
|
16
|
+
See here for searching on a fixed key in a JSONB column: https://activerecord-hackery.github.io/ransack/going-further/ransackers/#postgres-columns
|
17
17
|
|
18
18
|
### Using the JSONB contains operator
|
19
19
|
|
data/docs/package.json
CHANGED
@@ -14,15 +14,19 @@
|
|
14
14
|
"write-heading-ids": "docusaurus write-heading-ids"
|
15
15
|
},
|
16
16
|
"dependencies": {
|
17
|
-
"@docusaurus/core": "^2.
|
18
|
-
"@docusaurus/preset-classic": "^2.
|
19
|
-
"@easyops-cn/docusaurus-search-local": "^0.
|
17
|
+
"@docusaurus/core": "^2.2.0",
|
18
|
+
"@docusaurus/preset-classic": "^2.2.0",
|
19
|
+
"@easyops-cn/docusaurus-search-local": "^0.33.5",
|
20
20
|
"@mdx-js/react": "^1.6.22",
|
21
21
|
"clsx": "^1.1.1",
|
22
22
|
"prism-react-renderer": "^1.3.1",
|
23
23
|
"react": "^17.0.2",
|
24
24
|
"react-dom": "^17.0.2"
|
25
25
|
},
|
26
|
+
"resolutions": {
|
27
|
+
"trim": "^0.0.3",
|
28
|
+
"got": "^11.8.5"
|
29
|
+
},
|
26
30
|
"browserslist": {
|
27
31
|
"production": [
|
28
32
|
">0.5%",
|