ransack 2.1.1 → 2.5.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/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/cronjob.yml +102 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test.yml +163 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +64 -1
- data/CONTRIBUTING.md +16 -11
- data/Gemfile +23 -17
- data/README.md +190 -57
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +71 -0
- data/docs/img/create_release.png +0 -0
- data/docs/release_process.md +17 -0
- data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb +2 -9
- data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb +25 -3
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/polyamorous.rb +24 -0
- data/lib/polyamorous.rb +1 -25
- data/lib/ransack/adapters/active_record/base.rb +5 -1
- data/lib/ransack/adapters/active_record/context.rb +71 -68
- data/lib/ransack/adapters/active_record/ransack/constants.rb +18 -3
- data/lib/ransack/adapters/active_record/ransack/context.rb +2 -6
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +13 -5
- data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -1
- data/lib/ransack/configuration.rb +31 -1
- data/lib/ransack/constants.rb +3 -5
- data/lib/ransack/context.rb +19 -18
- data/lib/ransack/helpers/form_builder.rb +8 -14
- data/lib/ransack/helpers/form_helper.rb +1 -1
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/locale/az.yml +1 -1
- data/lib/ransack/locale/ca.yml +70 -0
- data/lib/ransack/locale/es.yml +22 -22
- data/lib/ransack/locale/fa.yml +70 -0
- data/lib/ransack/locale/fi.yml +71 -0
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +1 -1
- data/lib/ransack/nodes/condition.rb +7 -1
- data/lib/ransack/nodes/grouping.rb +1 -1
- data/lib/ransack/nodes/sort.rb +3 -3
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +2 -1
- data/lib/ransack/search.rb +4 -1
- data/lib/ransack/translate.rb +115 -115
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack.rb +3 -3
- data/ransack.gemspec +8 -23
- data/spec/blueprints/articles.rb +1 -1
- data/spec/blueprints/comments.rb +1 -1
- data/spec/blueprints/notes.rb +1 -1
- data/spec/blueprints/tags.rb +1 -1
- data/spec/console.rb +5 -5
- data/spec/helpers/polyamorous_helper.rb +3 -8
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/{ransack → polyamorous}/join_association_spec.rb +8 -1
- data/spec/{ransack → polyamorous}/join_dependency_spec.rb +18 -7
- data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +26 -15
- data/spec/ransack/adapters/active_record/context_spec.rb +60 -18
- data/spec/ransack/configuration_spec.rb +24 -0
- data/spec/ransack/helpers/form_helper_spec.rb +16 -16
- data/spec/ransack/nodes/condition_spec.rb +13 -0
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/predicate_spec.rb +54 -2
- data/spec/ransack/search_spec.rb +238 -36
- data/spec/spec_helper.rb +10 -5
- data/spec/support/schema.rb +37 -3
- metadata +45 -139
- data/.travis.yml +0 -37
- data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
- data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
- data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -32
- data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
- data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -32
- data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -113
data/README.md
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
# 
|
|
2
2
|
|
|
3
|
-
[](https://github.com/activerecord-hackery/ransack/actions)
|
|
4
4
|
[](http://badge.fury.io/rb/ransack)
|
|
5
5
|
[](https://codeclimate.com/github/activerecord-hackery/ransack)
|
|
6
|
-
[](#backers) [](#sponsors)
|
|
7
|
-
|
|
8
|
-
Ransack is a rewrite of [MetaSearch](https://github.com/activerecord-hackery/meta_search)
|
|
9
|
-
created by [Ernie Miller](http://twitter.com/erniemiller)
|
|
10
|
-
and developed/maintained for years by
|
|
11
|
-
[Jon Atack](http://twitter.com/jonatack) and
|
|
12
|
-
[Ryan Bigg](http://twitter.com/ryanbigg) with the help of a great group of
|
|
13
|
-
[contributors](https://github.com/activerecord-hackery/ransack/graphs/contributors). Ransack's logo is designed by [Anıl Kılıç](https://github.com/anilkilic).
|
|
14
|
-
While it supports many of the same features as MetaSearch, its underlying
|
|
15
|
-
implementation differs greatly from MetaSearch,
|
|
16
|
-
and backwards compatibility is not a design goal.
|
|
6
|
+
[](#backers) [](#sponsors)
|
|
17
7
|
|
|
18
8
|
Ransack enables the creation of both
|
|
19
9
|
[simple](http://ransack-demo.herokuapp.com) and
|
|
@@ -21,25 +11,11 @@ Ransack enables the creation of both
|
|
|
21
11
|
for your Ruby on Rails application
|
|
22
12
|
([demo source code here](https://github.com/activerecord-hackery/ransack_demo)).
|
|
23
13
|
If you're looking for something that simplifies query generation at the model
|
|
24
|
-
or controller layer, you're probably not looking for Ransack
|
|
25
|
-
for that matter). Try [Squeel](https://github.com/activerecord-hackery/squeel)
|
|
26
|
-
instead.
|
|
27
|
-
|
|
28
|
-
If you're viewing this at
|
|
29
|
-
[github.com/activerecord-hackery/ransack](https://github.com/activerecord-hackery/ransack),
|
|
30
|
-
you're reading the documentation for the master branch with the latest features.
|
|
31
|
-
[View documentation for the last release (2.0.0).](https://github.com/activerecord-hackery/ransack/tree/v2.0.0)
|
|
14
|
+
or controller layer, you're probably not looking for Ransack.
|
|
32
15
|
|
|
33
16
|
## Getting started
|
|
34
17
|
|
|
35
|
-
Ransack is
|
|
36
|
-
If you are using Rails <5.0 use the 1.8 line of Ransack.
|
|
37
|
-
If you are using Ruby 1.8 or an earlier JRuby and run into compatibility
|
|
38
|
-
issues, you can use an earlier version of Ransack, say, up to 1.3.0.
|
|
39
|
-
|
|
40
|
-
Ransack works out-of-the-box with Active Record and also features limited
|
|
41
|
-
support for Mongoid 4 and 5 (without associations, further details
|
|
42
|
-
[below](https://github.com/activerecord-hackery/ransack#mongoid)).
|
|
18
|
+
Ransack is supported for Rails 6.1, 6.0, 5.2 on Ruby 2.6.6 and later.
|
|
43
19
|
|
|
44
20
|
In your Gemfile, for the last officially released gem:
|
|
45
21
|
|
|
@@ -63,27 +39,14 @@ gem 'ransack', github: 'activerecord-hackery/ransack'
|
|
|
63
39
|
|
|
64
40
|
## Usage
|
|
65
41
|
|
|
66
|
-
Ransack can be used in one of two modes, simple or advanced.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
This mode works much like MetaSearch, for those of you who are familiar with
|
|
71
|
-
it, and requires very little setup effort.
|
|
72
|
-
|
|
73
|
-
If you're coming from MetaSearch, things to note:
|
|
42
|
+
Ransack can be used in one of two modes, simple or advanced. For
|
|
43
|
+
searching/filtering not requiring complex boolean logic, Ransack's simple
|
|
44
|
+
mode should meet your needs.
|
|
74
45
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
will still run afoul of URL length limits in most browsers and require a
|
|
78
|
-
switch to HTTP POST requests. This key is [configurable](https://github.com/activerecord-hackery/ransack/wiki/Configuration).
|
|
46
|
+
If you're coming from MetaSearch (Ransack's predecessor), refer to the
|
|
47
|
+
[Updating From MetaSearch](#updating-from-metasearch) section
|
|
79
48
|
|
|
80
|
-
|
|
81
|
-
object is passed to it.
|
|
82
|
-
|
|
83
|
-
3. Common ActiveRecord::Relation methods are no longer delegated by the
|
|
84
|
-
search object. Instead, you will get your search results (an
|
|
85
|
-
ActiveRecord::Relation in the case of the ActiveRecord adapter) via a call to
|
|
86
|
-
`Ransack#result`.
|
|
49
|
+
### Simple Mode
|
|
87
50
|
|
|
88
51
|
#### In your controller
|
|
89
52
|
|
|
@@ -100,9 +63,35 @@ this example, with preloading each Person's Articles and pagination):
|
|
|
100
63
|
def index
|
|
101
64
|
@q = Person.ransack(params[:q])
|
|
102
65
|
@people = @q.result.includes(:articles).page(params[:page])
|
|
66
|
+
end
|
|
67
|
+
```
|
|
103
68
|
|
|
104
|
-
|
|
105
|
-
|
|
69
|
+
##### Default search options
|
|
70
|
+
|
|
71
|
+
**Search parameter**
|
|
72
|
+
|
|
73
|
+
Ransack uses a default `:q` param key for search params. This may be changed by
|
|
74
|
+
setting the `search_key` option in a Ransack initializer file (typically
|
|
75
|
+
`config/initializers/ransack.rb`):
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
Ransack.configure do |c|
|
|
79
|
+
# Change default search parameter key name.
|
|
80
|
+
# Default key name is :q
|
|
81
|
+
c.search_key = :query
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**String search**
|
|
86
|
+
|
|
87
|
+
After version 2.4.0 when searching a string query Ransack by default strips all whitespace around the query string.
|
|
88
|
+
This may be disabled by setting the `strip_whitespace` option in a Ransack initializer file:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
Ransack.configure do |c|
|
|
92
|
+
# Change whitespace stripping behaviour.
|
|
93
|
+
# Default is true
|
|
94
|
+
c.strip_whitespace = false
|
|
106
95
|
end
|
|
107
96
|
```
|
|
108
97
|
|
|
@@ -272,6 +261,57 @@ the order indicator arrow by passing `hide_indicator: true` in the sort link:
|
|
|
272
261
|
default_order: { last_name: 'asc', first_name: 'desc' }) %>
|
|
273
262
|
```
|
|
274
263
|
|
|
264
|
+
#### PostgreSQL's sort option
|
|
265
|
+
|
|
266
|
+
The `NULLS FIRST` and `NULLS LAST` options can be used to determine whether nulls appear before or after non-null values in the sort ordering.
|
|
267
|
+
|
|
268
|
+
You may want to configure it like this:
|
|
269
|
+
|
|
270
|
+
```rb
|
|
271
|
+
Ransack.configure do |c|
|
|
272
|
+
c.postgres_fields_sort_option = :nulls_first # or :nulls_last
|
|
273
|
+
end
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
To treat nulls as having the lowest or highest value respectively. To force nulls to always be first or last, use
|
|
277
|
+
|
|
278
|
+
```rb
|
|
279
|
+
Ransack.configure do |c|
|
|
280
|
+
c.postgres_fields_sort_option = :nulls_always_first # or :nulls_always_last
|
|
281
|
+
end
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
|
285
|
+
|
|
286
|
+
#### Case Insensitive Sorting in PostgreSQL
|
|
287
|
+
|
|
288
|
+
In order to request PostgreSQL to do a case insensitive sort for all string columns of a model at once, Ransack can be extended by using this approach:
|
|
289
|
+
|
|
290
|
+
```ruby
|
|
291
|
+
module RansackObject
|
|
292
|
+
|
|
293
|
+
def self.included(base)
|
|
294
|
+
base.columns.each do |column|
|
|
295
|
+
if column.type == :string
|
|
296
|
+
base.ransacker column.name.to_sym, type: :string do
|
|
297
|
+
Arel.sql("lower(#{base.table_name}.#{column.name})")
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
class UserWithManyAttributes < ActiveRecord::Base
|
|
307
|
+
include RansackObject
|
|
308
|
+
end
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
If this approach is taken, it is advisable to [add a functional index](https://www.postgresql.org/docs/13/citext.html).
|
|
312
|
+
|
|
313
|
+
This was originally asked in [a Ransack issue](https://github.com/activerecord-hackery/ransack/issues/1201) and a solution was found on [Stack Overflow](https://stackoverflow.com/a/34677378).
|
|
314
|
+
|
|
275
315
|
### Advanced Mode
|
|
276
316
|
|
|
277
317
|
"Advanced" searches (ab)use Rails' nested attributes functionality in order to
|
|
@@ -430,6 +470,25 @@ query parameters in your URLs.
|
|
|
430
470
|
<% end %>
|
|
431
471
|
```
|
|
432
472
|
|
|
473
|
+
You can also use `ransack_alias` for sorting.
|
|
474
|
+
|
|
475
|
+
```ruby
|
|
476
|
+
class Post < ActiveRecord::Base
|
|
477
|
+
belongs_to :author
|
|
478
|
+
|
|
479
|
+
# Abbreviate :author_first_name to :author
|
|
480
|
+
ransack_alias :author, :author_first_name
|
|
481
|
+
end
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Now, you can use `:author` instead of `:author_first_name` in a `sort_link`.
|
|
485
|
+
|
|
486
|
+
```erb
|
|
487
|
+
<%= sort_link(@q, :author) %>
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Note that using `:author_first_name_or_author_last_name_cont` would produce an invalid sql query. In those cases, Ransack ignores the sorting clause.
|
|
491
|
+
|
|
433
492
|
### Search Matchers
|
|
434
493
|
|
|
435
494
|
List of all possible predicates
|
|
@@ -459,13 +518,10 @@ List of all possible predicates
|
|
|
459
518
|
| `*_lteq_any` | Less than or equal to any | |
|
|
460
519
|
| `*_gt_any` | Greater than any | |
|
|
461
520
|
| `*_gteq_any` | Greater than or equal to any | |
|
|
462
|
-
| `*_matches_any` | `*_does_not_match_any` | same as above but with `LIKE` |
|
|
463
521
|
| `*_lt_all` | Less than all | SQL: `col < value1 AND col < value2` |
|
|
464
522
|
| `*_lteq_all` | Less than or equal to all | |
|
|
465
523
|
| `*_gt_all` | Greater than all | |
|
|
466
524
|
| `*_gteq_all` | Greater than or equal to all | |
|
|
467
|
-
| `*_matches_all` | Matches all | same as above but with `LIKE` |
|
|
468
|
-
| `*_does_not_match_all` | Does not match all | |
|
|
469
525
|
| `*_not_eq_all` | none of values in a set | |
|
|
470
526
|
| `*_start` | Starts with | SQL: `col LIKE 'value%'` |
|
|
471
527
|
| `*_not_start` | Does not start with | |
|
|
@@ -485,6 +541,12 @@ List of all possible predicates
|
|
|
485
541
|
| `*_not_cont` | Does not contain |
|
|
486
542
|
| `*_not_cont_any` | Does not contain any of | |
|
|
487
543
|
| `*_not_cont_all` | Does not contain all of | |
|
|
544
|
+
| `*_i_cont` | Contains value with case insensitive | uses `ILIKE` |
|
|
545
|
+
| `*_i_cont_any` | Contains any of values with case insensitive | |
|
|
546
|
+
| `*_i_cont_all` | Contains all of values with case insensitive | |
|
|
547
|
+
| `*_not_i_cont` | Does not contain with case insensitive |
|
|
548
|
+
| `*_not_i_cont_any` | Does not contain any of values with case insensitive | |
|
|
549
|
+
| `*_not_i_cont_all` | Does not contain all of values with case insensitive | |
|
|
488
550
|
| `*_true` | is true | |
|
|
489
551
|
| `*_false` | is false | |
|
|
490
552
|
|
|
@@ -689,6 +751,43 @@ Trying it out in `rails console`:
|
|
|
689
751
|
|
|
690
752
|
That's it! Now you know how to whitelist/blacklist various elements in Ransack.
|
|
691
753
|
|
|
754
|
+
### Handling unknown predicates or attributes
|
|
755
|
+
|
|
756
|
+
By default, Ransack will ignore any unknown predicates or attributes:
|
|
757
|
+
|
|
758
|
+
```ruby
|
|
759
|
+
Article.ransack(unknown_attr_eq: 'Ernie').result.to_sql
|
|
760
|
+
=> SELECT "articles".* FROM "articles"
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Ransack may be configured to raise an error if passed an unknown predicate or
|
|
764
|
+
attributes, by setting the `ignore_unknown_conditions` option to `false` in your
|
|
765
|
+
Ransack initializer file at `config/initializers/ransack.rb`:
|
|
766
|
+
|
|
767
|
+
```ruby
|
|
768
|
+
Ransack.configure do |c|
|
|
769
|
+
# Raise errors if a query contains an unknown predicate or attribute.
|
|
770
|
+
# Default is true (do not raise error on unknown conditions).
|
|
771
|
+
c.ignore_unknown_conditions = false
|
|
772
|
+
end
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
```ruby
|
|
776
|
+
Article.ransack(unknown_attr_eq: 'Ernie')
|
|
777
|
+
# ArgumentError (Invalid search term unknown_attr_eq)
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
As an alternative to setting a global configuration option, the `.ransack!`
|
|
781
|
+
class method also raises an error if passed an unknown condition:
|
|
782
|
+
|
|
783
|
+
```ruby
|
|
784
|
+
Article.ransack!(unknown_attr_eq: 'Ernie')
|
|
785
|
+
# ArgumentError: Invalid search term unknown_attr_eq
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
This is equivalent to the `ignore_unknown_conditions` configuration option,
|
|
789
|
+
except it may be applied on a case-by-case basis.
|
|
790
|
+
|
|
692
791
|
### Using Scopes/Class Methods
|
|
693
792
|
|
|
694
793
|
Continuing on from the preceding section, searching by scopes requires defining
|
|
@@ -717,8 +816,6 @@ class Employee < ActiveRecord::Base
|
|
|
717
816
|
%i(activated hired_since)
|
|
718
817
|
end
|
|
719
818
|
end
|
|
720
|
-
|
|
721
|
-
private_class_method :ransackable_scopes
|
|
722
819
|
end
|
|
723
820
|
|
|
724
821
|
Employee.ransack({ activated: true, hired_since: '2013-01-01' })
|
|
@@ -753,7 +850,7 @@ To turn this off on a per-scope basis Ransack adds the following method to
|
|
|
753
850
|
Add the scope you wish to bypass this behavior to ransackable_scopes_skip_sanitize_args:
|
|
754
851
|
|
|
755
852
|
```ruby
|
|
756
|
-
def ransackable_scopes_skip_sanitize_args
|
|
853
|
+
def self.ransackable_scopes_skip_sanitize_args
|
|
757
854
|
[:scope_to_skip_sanitize_args]
|
|
758
855
|
end
|
|
759
856
|
```
|
|
@@ -887,6 +984,28 @@ en:
|
|
|
887
984
|
title: Old Ransack Namespaced Title
|
|
888
985
|
```
|
|
889
986
|
|
|
987
|
+
### Updating From MetaSearch
|
|
988
|
+
|
|
989
|
+
Ransack works much like MetaSearch, for those of you who are familiar with
|
|
990
|
+
it, and requires very little setup effort.
|
|
991
|
+
|
|
992
|
+
If you're coming from MetaSearch, things to note:
|
|
993
|
+
|
|
994
|
+
1. The default param key for search params is now `:q`, instead of `:search`.
|
|
995
|
+
This is primarily to shorten query strings, though advanced queries (below)
|
|
996
|
+
will still run afoul of URL length limits in most browsers and require a
|
|
997
|
+
switch to HTTP POST requests. This key is
|
|
998
|
+
[configurable](default-search-parameter) via setting the `search_key` option
|
|
999
|
+
in your Ransack intitializer file.
|
|
1000
|
+
|
|
1001
|
+
2. `form_for` is now `search_form_for`, and validates that a Ransack::Search
|
|
1002
|
+
object is passed to it.
|
|
1003
|
+
|
|
1004
|
+
3. Common ActiveRecord::Relation methods are no longer delegated by the
|
|
1005
|
+
search object. Instead, you will get your search results (an
|
|
1006
|
+
ActiveRecord::Relation in the case of the ActiveRecord adapter) via a call to
|
|
1007
|
+
`Ransack#result`.
|
|
1008
|
+
|
|
890
1009
|
## Mongoid
|
|
891
1010
|
|
|
892
1011
|
Mongoid support has been moved to its own gem at [ransack-mongoid](https://github.com/activerecord-hackery/ransack-mongoid).
|
|
@@ -924,6 +1043,7 @@ In other words: `Major.Minor.Patch`.
|
|
|
924
1043
|
|
|
925
1044
|
To support the project:
|
|
926
1045
|
|
|
1046
|
+
* Consider supporting via [Open Collective](https://opencollective.com/ransack/backers/badge.svg)
|
|
927
1047
|
* Use Ransack in your apps, and let us know if you encounter anything that's
|
|
928
1048
|
broken or missing. A failing spec to demonstrate the issue is awesome. A pull
|
|
929
1049
|
request with passing tests is even better!
|
|
@@ -939,6 +1059,21 @@ fix bugs!
|
|
|
939
1059
|
|
|
940
1060
|
This project exists thanks to all the people who contribute. <img src="https://opencollective.com/ransack/contributors.svg?width=890&button=false" />
|
|
941
1061
|
|
|
1062
|
+
Ransack is a rewrite of [MetaSearch](https://github.com/activerecord-hackery/meta_search)
|
|
1063
|
+
created by [Ernie Miller](http://twitter.com/erniemiller)
|
|
1064
|
+
and developed/maintained by:
|
|
1065
|
+
|
|
1066
|
+
- [Greg Molnar](https://github.com/gregmolnar)
|
|
1067
|
+
- [Deivid Rodriguez](https://github.com/deivid-rodriguez)
|
|
1068
|
+
- [Sean Carroll](https://github.com/seanfcarroll)
|
|
1069
|
+
- [Jon Atack](http://twitter.com/jonatack)
|
|
1070
|
+
- [Ryan Bigg](http://twitter.com/ryanbigg)
|
|
1071
|
+
- a great group of [contributors](https://github.com/activerecord-hackery/ransack/graphs/contributors).
|
|
1072
|
+
- Ransack's logo is designed by [Anıl Kılıç](https://github.com/anilkilic).
|
|
1073
|
+
|
|
1074
|
+
While it supports many of the same features as MetaSearch, its underlying implementation differs greatly from MetaSearch, and backwards compatibility is not a design goal.
|
|
1075
|
+
|
|
1076
|
+
|
|
942
1077
|
|
|
943
1078
|
## Backers
|
|
944
1079
|
|
|
@@ -961,5 +1096,3 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
|
|
961
1096
|
<a href="https://opencollective.com/ransack/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/7/avatar.svg"></a>
|
|
962
1097
|
<a href="https://opencollective.com/ransack/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/8/avatar.svg"></a>
|
|
963
1098
|
<a href="https://opencollective.com/ransack/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ransack/sponsor/9/avatar.svg"></a>
|
|
964
|
-
|
|
965
|
-
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# test-ransack-scope-and-column-same-name.rb
|
|
2
|
+
|
|
3
|
+
# This is a stand-alone test case.
|
|
4
|
+
|
|
5
|
+
# Run it in your console with: `ruby test-ransack-scope-and-column-same-name.rb`
|
|
6
|
+
|
|
7
|
+
# If you change the gem dependencies, run it with:
|
|
8
|
+
# `rm gemfile* && ruby test-ransack-scope-and-column-same-name.rb`
|
|
9
|
+
|
|
10
|
+
unless File.exist?('Gemfile')
|
|
11
|
+
File.write('Gemfile', <<-GEMFILE)
|
|
12
|
+
source 'https://rubygems.org'
|
|
13
|
+
|
|
14
|
+
# Rails master
|
|
15
|
+
gem 'rails', github: 'rails/rails', branch: '6-1-stable'
|
|
16
|
+
|
|
17
|
+
# Rails last release
|
|
18
|
+
# gem 'rails'
|
|
19
|
+
|
|
20
|
+
gem 'sqlite3'
|
|
21
|
+
gem 'ransack', github: 'activerecord-hackery/ransack'
|
|
22
|
+
GEMFILE
|
|
23
|
+
|
|
24
|
+
system 'bundle install'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
require 'bundler'
|
|
28
|
+
Bundler.setup(:default)
|
|
29
|
+
|
|
30
|
+
require 'active_record'
|
|
31
|
+
require 'minitest/autorun'
|
|
32
|
+
require 'logger'
|
|
33
|
+
require 'ransack'
|
|
34
|
+
|
|
35
|
+
# This connection will do for database-independent bug reports.
|
|
36
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
|
37
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
38
|
+
|
|
39
|
+
# Display versions.
|
|
40
|
+
message = "Running test case with Ruby #{RUBY_VERSION}, Active Record #{
|
|
41
|
+
::ActiveRecord::VERSION::STRING}, Arel #{Arel::VERSION} and #{
|
|
42
|
+
::ActiveRecord::Base.connection.adapter_name}"
|
|
43
|
+
line = '=' * message.length
|
|
44
|
+
puts line, message, line
|
|
45
|
+
|
|
46
|
+
ActiveRecord::Schema.define do
|
|
47
|
+
create_table :users, force: true do |t|
|
|
48
|
+
t.boolean :active, null: false, default: true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class User < ActiveRecord::Base
|
|
53
|
+
scope :activated, -> (boolean = true) { where(active: boolean) }
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def self.ransackable_scopes(auth_object = nil)
|
|
58
|
+
%i(activated)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class BugTest < Minitest::Test
|
|
63
|
+
def test_activated_scope_equals_true
|
|
64
|
+
sql = User.ransack({ activated: true }).result.to_sql
|
|
65
|
+
puts sql
|
|
66
|
+
assert_equal(
|
|
67
|
+
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"active\" = 1", sql
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_activated_scope_equals_false
|
|
72
|
+
sql = User.ransack({ activated: false }).result.to_sql
|
|
73
|
+
puts sql
|
|
74
|
+
assert_equal(
|
|
75
|
+
"SELECT \"users\".* FROM \"users\"", sql
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# test-ransacker-arel-present-predicate.rb
|
|
2
|
+
|
|
3
|
+
# Run it in your console with: `ruby test-ransacker-arel-present-predicate.rb`
|
|
4
|
+
|
|
5
|
+
# If you change the gem dependencies, run it with:
|
|
6
|
+
# `rm gemfile* && ruby test-ransacker-arel-present-predicate.rb`
|
|
7
|
+
|
|
8
|
+
unless File.exist?('Gemfile')
|
|
9
|
+
File.write('Gemfile', <<-GEMFILE)
|
|
10
|
+
source 'https://rubygems.org'
|
|
11
|
+
|
|
12
|
+
# Rails master
|
|
13
|
+
gem 'rails', github: 'rails/rails', branch: '6-1-stable'
|
|
14
|
+
|
|
15
|
+
# Rails last release
|
|
16
|
+
# gem 'rails'
|
|
17
|
+
|
|
18
|
+
gem 'sqlite3'
|
|
19
|
+
gem 'ransack', github: 'activerecord-hackery/ransack'
|
|
20
|
+
GEMFILE
|
|
21
|
+
|
|
22
|
+
system 'bundle install'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require 'bundler'
|
|
26
|
+
Bundler.setup(:default)
|
|
27
|
+
|
|
28
|
+
require 'active_record'
|
|
29
|
+
require 'minitest/autorun'
|
|
30
|
+
require 'logger'
|
|
31
|
+
require 'ransack'
|
|
32
|
+
|
|
33
|
+
# This connection will do for database-independent bug reports.
|
|
34
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
|
35
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
36
|
+
|
|
37
|
+
# Display versions.
|
|
38
|
+
message = "Running test case with Ruby #{RUBY_VERSION}, Active Record #{
|
|
39
|
+
::ActiveRecord::VERSION::STRING}, Arel #{Arel::VERSION} and #{
|
|
40
|
+
::ActiveRecord::Base.connection.adapter_name}"
|
|
41
|
+
line = '=' * message.length
|
|
42
|
+
puts line, message, line
|
|
43
|
+
|
|
44
|
+
ActiveRecord::Schema.define do
|
|
45
|
+
create_table :projects, force: true do |t|
|
|
46
|
+
t.string :name
|
|
47
|
+
t.string :number
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Project < ActiveRecord::Base
|
|
52
|
+
ransacker :name do
|
|
53
|
+
Arel.sql('projects.name')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ransacker :number do |parent|
|
|
57
|
+
parent.table[:number]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class BugTest < Minitest::Test
|
|
62
|
+
def test_ransackers
|
|
63
|
+
sql = Project.ransack({ number_present: 1 }).result.to_sql
|
|
64
|
+
puts sql
|
|
65
|
+
assert_equal "SELECT \"projects\".* FROM \"projects\" WHERE (\"projects\".\"number\" IS NOT NULL AND \"projects\".\"number\" != '')", sql
|
|
66
|
+
|
|
67
|
+
sql = Project.ransack({ name_present: 1 }).result.to_sql
|
|
68
|
+
puts sql
|
|
69
|
+
assert_equal "SELECT \"projects\".* FROM \"projects\" WHERE (projects.name IS NOT NULL AND projects.name != '')", sql
|
|
70
|
+
end
|
|
71
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## Release Process
|
|
2
|
+
|
|
3
|
+
*For maintainers of Ransack.*
|
|
4
|
+
|
|
5
|
+
To release a new version of Ransack and publish it to RubyGems, take the following steps:
|
|
6
|
+
|
|
7
|
+
- Create a new release, marked `Prerelease`.
|
|
8
|
+
- Update the versions file to the new release, commit and push to `master`.
|
|
9
|
+
- Update the [`version.rb`](../lib/ransack/version.rb) file to the new release, commit and push to `master`.
|
|
10
|
+
- From the terminal, run the following commands:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
rake build
|
|
14
|
+
rake release
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+

|
data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb
RENAMED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# active_record_5.2.1_ruby_2/join_association.rb
|
|
2
|
-
|
|
3
1
|
module Polyamorous
|
|
4
2
|
module JoinAssociationExtensions
|
|
5
3
|
include SwappingReflectionClass
|
|
@@ -19,13 +17,8 @@ module Polyamorous
|
|
|
19
17
|
end
|
|
20
18
|
end
|
|
21
19
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
super(klass, table, key, foreign_table, foreign_key)
|
|
25
|
-
.and(foreign_table[reflection.foreign_type].eq(reflection.klass.name))
|
|
26
|
-
else
|
|
27
|
-
super(klass, table, key, foreign_table, foreign_key)
|
|
28
|
-
end
|
|
20
|
+
def ==(other)
|
|
21
|
+
base_klass == other.base_klass
|
|
29
22
|
end
|
|
30
23
|
end
|
|
31
24
|
end
|
data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb
RENAMED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
# active_record_5.2.1_ruby_2/join_dependency.rb
|
|
2
|
-
|
|
3
1
|
module Polyamorous
|
|
4
2
|
module JoinDependencyExtensions
|
|
5
3
|
# Replaces ActiveRecord::Associations::JoinDependency#build
|
|
6
|
-
#
|
|
7
4
|
def build(associations, base_klass)
|
|
8
5
|
associations.map do |name, right|
|
|
9
6
|
if name.is_a? Join
|
|
@@ -30,6 +27,31 @@ module Polyamorous
|
|
|
30
27
|
end
|
|
31
28
|
end
|
|
32
29
|
|
|
30
|
+
def join_constraints(joins_to_add, join_type, alias_tracker)
|
|
31
|
+
@alias_tracker = alias_tracker
|
|
32
|
+
|
|
33
|
+
construct_tables!(join_root)
|
|
34
|
+
joins = make_join_constraints(join_root, join_type)
|
|
35
|
+
|
|
36
|
+
joins.concat joins_to_add.flat_map { |oj|
|
|
37
|
+
construct_tables!(oj.join_root)
|
|
38
|
+
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
|
39
|
+
walk join_root, oj.join_root
|
|
40
|
+
else
|
|
41
|
+
make_join_constraints(oj.join_root, join_type)
|
|
42
|
+
end
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
|
48
|
+
foreign_table = parent.table
|
|
49
|
+
foreign_klass = parent.base_klass
|
|
50
|
+
join_type = child.join_type || join_type if join_type == Arel::Nodes::InnerJoin
|
|
51
|
+
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
|
52
|
+
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
|
53
|
+
end
|
|
54
|
+
|
|
33
55
|
module ClassMethods
|
|
34
56
|
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
|
35
57
|
#
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'polyamorous/activerecord_5.2_ruby_2/join_association'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# active_record_6.0_ruby_2/join_dependency.rb
|
|
2
|
+
module Polyamorous
|
|
3
|
+
module JoinDependencyExtensions
|
|
4
|
+
# Replaces ActiveRecord::Associations::JoinDependency#build
|
|
5
|
+
def build(associations, base_klass)
|
|
6
|
+
associations.map do |name, right|
|
|
7
|
+
if name.is_a? Join
|
|
8
|
+
reflection = find_reflection base_klass, name.name
|
|
9
|
+
reflection.check_validity!
|
|
10
|
+
reflection.check_eager_loadable!
|
|
11
|
+
|
|
12
|
+
klass = if reflection.polymorphic?
|
|
13
|
+
name.klass || base_klass
|
|
14
|
+
else
|
|
15
|
+
reflection.klass
|
|
16
|
+
end
|
|
17
|
+
JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
|
|
18
|
+
else
|
|
19
|
+
reflection = find_reflection base_klass, name
|
|
20
|
+
reflection.check_validity!
|
|
21
|
+
reflection.check_eager_loadable!
|
|
22
|
+
|
|
23
|
+
if reflection.polymorphic?
|
|
24
|
+
raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
|
|
25
|
+
end
|
|
26
|
+
JoinAssociation.new(reflection, build(right, reflection.klass))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def join_constraints(joins_to_add, alias_tracker)
|
|
32
|
+
@alias_tracker = alias_tracker
|
|
33
|
+
|
|
34
|
+
construct_tables!(join_root)
|
|
35
|
+
joins = make_join_constraints(join_root, join_type)
|
|
36
|
+
|
|
37
|
+
joins.concat joins_to_add.flat_map { |oj|
|
|
38
|
+
construct_tables!(oj.join_root)
|
|
39
|
+
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
|
40
|
+
walk join_root, oj.join_root, oj.join_type
|
|
41
|
+
else
|
|
42
|
+
make_join_constraints(oj.join_root, oj.join_type)
|
|
43
|
+
end
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
|
49
|
+
foreign_table = parent.table
|
|
50
|
+
foreign_klass = parent.base_klass
|
|
51
|
+
join_type = child.join_type || join_type if join_type == Arel::Nodes::InnerJoin
|
|
52
|
+
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
|
53
|
+
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
module ClassMethods
|
|
57
|
+
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
|
58
|
+
#
|
|
59
|
+
def walk_tree(associations, hash)
|
|
60
|
+
case associations
|
|
61
|
+
when TreeNode
|
|
62
|
+
associations.add_to_tree(hash)
|
|
63
|
+
when Hash
|
|
64
|
+
associations.each do |k, v|
|
|
65
|
+
cache =
|
|
66
|
+
if TreeNode === k
|
|
67
|
+
k.add_to_tree(hash)
|
|
68
|
+
else
|
|
69
|
+
hash[k] ||= {}
|
|
70
|
+
end
|
|
71
|
+
walk_tree(v, cache)
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
super(associations, hash)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'polyamorous/activerecord_5.2_ruby_2/reflection'
|