ransack 3.2.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql.yml +72 -0
  3. data/.github/workflows/cronjob.yml +6 -9
  4. data/.github/workflows/deploy.yml +1 -1
  5. data/.github/workflows/rubocop.yml +2 -2
  6. data/.github/workflows/test-deploy.yml +1 -1
  7. data/.github/workflows/test.yml +23 -22
  8. data/.rubocop.yml +7 -1
  9. data/CHANGELOG.md +86 -0
  10. data/CONTRIBUTING.md +40 -21
  11. data/Gemfile +10 -10
  12. data/README.md +4 -9
  13. data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +1 -1
  14. data/bug_report_templates/test-ransacker-arel-present-predicate.rb +5 -1
  15. data/docs/docs/getting-started/advanced-mode.md +1 -1
  16. data/docs/docs/getting-started/search-matches.md +1 -1
  17. data/docs/docs/getting-started/simple-mode.md +6 -2
  18. data/docs/docs/getting-started/sorting.md +45 -53
  19. data/docs/docs/going-further/acts-as-taggable-on.md +4 -4
  20. data/docs/docs/going-further/form-customisation.md +1 -1
  21. data/docs/docs/going-further/i18n.md +3 -3
  22. data/docs/docs/going-further/other-notes.md +2 -2
  23. data/docs/docs/going-further/polymorphic-search.md +6 -0
  24. data/docs/docs/going-further/saving-queries.md +1 -1
  25. data/docs/docs/going-further/searching-postgres.md +1 -1
  26. data/docs/package.json +7 -3
  27. data/docs/yarn.lock +2371 -1928
  28. data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +14 -4
  29. data/lib/ransack/adapters/active_record/base.rb +78 -7
  30. data/lib/ransack/adapters/active_record/context.rb +2 -1
  31. data/lib/ransack/configuration.rb +25 -12
  32. data/lib/ransack/constants.rb +125 -0
  33. data/lib/ransack/context.rb +34 -5
  34. data/lib/ransack/helpers/form_builder.rb +3 -3
  35. data/lib/ransack/helpers/form_helper.rb +3 -2
  36. data/lib/ransack/nodes/attribute.rb +2 -2
  37. data/lib/ransack/nodes/condition.rb +80 -7
  38. data/lib/ransack/nodes/grouping.rb +3 -3
  39. data/lib/ransack/nodes/node.rb +1 -1
  40. data/lib/ransack/nodes/value.rb +1 -1
  41. data/lib/ransack/predicate.rb +1 -1
  42. data/lib/ransack/ransacker.rb +1 -1
  43. data/lib/ransack/search.rb +9 -4
  44. data/lib/ransack/translate.rb +2 -2
  45. data/lib/ransack/version.rb +1 -1
  46. data/lib/ransack/visitor.rb +38 -2
  47. data/lib/ransack.rb +3 -6
  48. data/ransack.gemspec +1 -1
  49. data/spec/ransack/adapters/active_record/base_spec.rb +89 -0
  50. data/spec/ransack/configuration_spec.rb +9 -9
  51. data/spec/ransack/helpers/form_builder_spec.rb +8 -8
  52. data/spec/ransack/helpers/form_helper_spec.rb +36 -2
  53. data/spec/ransack/nodes/condition_spec.rb +24 -0
  54. data/spec/ransack/predicate_spec.rb +36 -1
  55. data/spec/ransack/translate_spec.rb +1 -1
  56. data/spec/support/schema.rb +55 -10
  57. metadata +6 -13
  58. data/lib/polyamorous.rb +0 -1
  59. data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -128
  60. data/lib/ransack/adapters/active_record/ransack/context.rb +0 -56
  61. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +0 -61
  62. data/lib/ransack/adapters/active_record/ransack/translate.rb +0 -8
  63. data/lib/ransack/adapters/active_record/ransack/visitor.rb +0 -47
  64. data/lib/ransack/adapters.rb +0 -64
  65. data/lib/ransack/nodes.rb +0 -8
  66. /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 behaviour.
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
- <div class="filters" id="filtersSidebar">
14
- <header class="filters-header">
15
- <div class="filters-header-content">
16
- <h3>Filters</h3>
17
- </div>
18
- </header>
19
-
20
- <div class="filters-content">
21
- <%= search_form_for @q,
22
- class: 'form',
23
- url: articles_path,
24
- html: { autocomplete: 'off', autocapitalize: 'none' } do |f| %>
25
-
26
- <div class="form-group">
27
- <%= f.label :title_cont, t('Filter_by_keyword') %>
28
- <%= f.search_field :title_cont %>
29
- </div>
30
-
31
- <%= render partial: 'filters/date_title_sort', locals: { f: f } %>
32
-
33
- <div class="form-group">
34
- <%= f.label :grade_level_gteq, t('Grade_level') %> >=
35
- <%= f.search_field :grade_level_gteq %>
36
- </div>
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
- </div>
59
- </div>
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
- @search = Post.ransack(params[:q])
69
- @search.sorts = 'name asc' if @search.sorts.empty?
70
- @posts = @search.result.paginate(page: params[:page], per_page: 20)
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
- @search = Post.ransack(params[:q])
77
- @search.sorts = ['name asc', 'created_at desc'] if @search.sorts.empty?
78
- @posts = @search.result.paginate(page: params[:page], per_page: 20)
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 `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):
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 `b` will match all keys exactly. This is the solution if you wanna search for specific combinations of tags:
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 `c` is used to match substrings. This is useful when you don't care for the exact tag, but only for part of it:
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 againt them. We use the plural name here.
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/activerecord-hackery/ransack/tree/master/lib/ransack/locale) for more examples):
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: Passanger
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](http://erniemiller.org/2012/05/11/why-your-ruby-class-macros-might-suck-mine-did/).
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://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers) instead,
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 TEH CONTROLLER NAME
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://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers#3-search-on-a-fixed-key-in-a-jsonb--hstore-column
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.0.0-beta.20",
18
- "@docusaurus/preset-classic": "^2.0.0-beta.20",
19
- "@easyops-cn/docusaurus-search-local": "^0.25.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%",