mirror of
https://github.com/activerecord-hackery/ransack.git
synced 2022-11-09 13:47:45 -05:00
Merge branch 'master' into allow-scopes-with-string-joins
This commit is contained in:
commit
1c69b9ddbf
31 changed files with 413 additions and 302 deletions
12
.github/workflows/cronjob.yml
vendored
12
.github/workflows/cronjob.yml
vendored
|
@ -11,8 +11,8 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
env:
|
||||
DB: sqlite3
|
||||
RAILS: main
|
||||
|
@ -33,8 +33,8 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
env:
|
||||
DB: mysql
|
||||
RAILS: main
|
||||
|
@ -64,8 +64,8 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
env:
|
||||
DB: postgres
|
||||
RAILS: main
|
||||
|
|
2
.github/workflows/rubocop.yml
vendored
2
.github/workflows/rubocop.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.0.0
|
||||
ruby-version: 3.0.1
|
||||
- name: Install gems
|
||||
run: bundle install --jobs 4 --retry 3
|
||||
- name: Run RuboCop
|
||||
|
|
59
.github/workflows/test.yml
vendored
59
.github/workflows/test.yml
vendored
|
@ -11,20 +11,17 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
rails:
|
||||
- v6.1.3
|
||||
- v6.0.3
|
||||
- v7.0.0
|
||||
- v6.1.4
|
||||
- v6.0.4
|
||||
- 6-0-stable
|
||||
- 5-2-stable
|
||||
- v5.2.4
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 2.6.6
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
- 2.6.7
|
||||
exclude:
|
||||
- rails: v5.2.4
|
||||
ruby: 3.0.0
|
||||
- rails: 5-2-stable
|
||||
ruby: 3.0.0
|
||||
- rails: v7.0.0
|
||||
ruby: 2.6.7
|
||||
env:
|
||||
DB: sqlite3
|
||||
RAILS: ${{ matrix.rails }}
|
||||
|
@ -45,20 +42,17 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
rails:
|
||||
- v6.1.3
|
||||
- v6.0.3
|
||||
- v7.0.0
|
||||
- v6.1.4
|
||||
- v6.0.4
|
||||
- 6-0-stable
|
||||
- 5-2-stable
|
||||
- v5.2.4
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 2.6.6
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
- 2.6.7
|
||||
exclude:
|
||||
- rails: v5.2.4
|
||||
ruby: 3.0.0
|
||||
- rails: 5-2-stable
|
||||
ruby: 3.0.0
|
||||
- rails: v7.0.0
|
||||
ruby: 2.6.7
|
||||
env:
|
||||
DB: mysql
|
||||
RAILS: ${{ matrix.rails }}
|
||||
|
@ -88,20 +82,17 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
rails:
|
||||
- v6.1.3
|
||||
- v6.0.3
|
||||
- v7.0.0
|
||||
- v6.1.4
|
||||
- v6.0.4
|
||||
- 6-0-stable
|
||||
- 5-2-stable
|
||||
- v5.2.4
|
||||
ruby:
|
||||
- 3.0.0
|
||||
- 2.7.2
|
||||
- 2.6.6
|
||||
- 3.0.2
|
||||
- 2.7.4
|
||||
- 2.6.7
|
||||
exclude:
|
||||
- rails: v5.2.4
|
||||
ruby: 3.0.0
|
||||
- rails: 5-2-stable
|
||||
ruby: 3.0.0
|
||||
- rails: v7.0.0
|
||||
ruby: 2.6.7
|
||||
env:
|
||||
DB: postgres
|
||||
RAILS: ${{ matrix.rails }}
|
||||
|
@ -144,7 +135,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.0.0
|
||||
ruby-version: 3.0.2
|
||||
- name: Install dependencies
|
||||
run: bundle install
|
||||
- name: Run bug report templates
|
||||
|
|
85
CHANGELOG.md
85
CHANGELOG.md
|
@ -1,22 +1,83 @@
|
|||
# Change Log
|
||||
|
||||
* Drop support for rubies under 2.5. PR #1189
|
||||
## Unreleased
|
||||
|
||||
* Improve `sort_link` documentation.
|
||||
|
||||
* Deprecate passing two trailing hashes to `sort_link`, for example:
|
||||
|
||||
```ruby
|
||||
sort_link(@q, :bussiness_name, "bussines_name", {}, class: "foo")
|
||||
```
|
||||
|
||||
Pass a single hash with all options instead.
|
||||
|
||||
* Fix `:class` option to `sort_link` not being passed to the generated link
|
||||
correctly when no additional options are passed. For example:
|
||||
|
||||
```ruby
|
||||
sort_link(@q, :bussiness_name, class: "foo")
|
||||
```
|
||||
|
||||
## 2.6.0 - 2022-03-08
|
||||
|
||||
* Fix regression when joining a table with itself.
|
||||
PR [1275](https://github.com/activerecord-hackery/ransack/pull/1276)
|
||||
|
||||
* Drop support for ActiveRecord older than 6.0.4.
|
||||
PR [1276](https://github.com/activerecord-hackery/ransack/pull/1276)
|
||||
|
||||
## 2.5.0 - 2021-12-26
|
||||
|
||||
* Document release process by @scarroll32 in https://github.com/activerecord-hackery/ransack/pull/1199, https://github.com/activerecord-hackery/ransack/pull/1200.
|
||||
* Support Rails 7 by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1205, https://github.com/activerecord-hackery/ransack/pull/1209, https://github.com/activerecord-hackery/ransack/pull/1234, https://github.com/activerecord-hackery/ransack/pull/1230, https://github.com/activerecord-hackery/ransack/pull/1266
|
||||
* Fix for `ActiveRecord::UnknownAttributeReference` in ransack by @TechnologyHypofriend in https://github.com/activerecord-hackery/ransack/pull/1207
|
||||
* Make gem compatible with old polyamorous require by @rtweeks in https://github.com/activerecord-hackery/ransack/pull/1145
|
||||
* Adding swedish translations by @johanandre in https://github.com/activerecord-hackery/ransack/pull/1208
|
||||
* Document how to do case insensitive searches by @scarroll32 in https://github.com/activerecord-hackery/ransack/pull/1213
|
||||
* Add the ability to disable whitespace stripping for string searches by @DCrow in https://github.com/activerecord-hackery/ransack/pull/1214
|
||||
* Fix `:default` option in `Translate.attribute` method by @coreyaus in https://github.com/activerecord-hackery/ransack/pull/1218
|
||||
* Fix typo in README.md by @d-m-u in https://github.com/activerecord-hackery/ransack/pull/1220
|
||||
* Fix another typo in README.md by @plan-do-break-fix in https://github.com/activerecord-hackery/ransack/pull/1221
|
||||
* Fix several documentation typos @wonda-tea-coffee in https://github.com/activerecord-hackery/ransack/pull/1233
|
||||
* Allow ransack to treat nulls as always first or last by @mollerhoj in https://github.com/activerecord-hackery/ransack/pull/1226
|
||||
* Consider ransack aliases when sorting by @faragorn and @waldyr in https://github.com/activerecord-hackery/ransack/pull/1223
|
||||
* Fix non-casted array predicates by @danielpclark in https://github.com/activerecord-hackery/ransack/pull/1246
|
||||
* Remove Squeel references from README by @Schwad in https://github.com/activerecord-hackery/ransack/pull/1249
|
||||
* Remove part of the README that might lead to incorrect results by @RadekMolenda in https://github.com/activerecord-hackery/ransack/pull/1258
|
||||
* ActiveRecord 7.0 support
|
||||
|
||||
## 2.4.2 - 2021-01-23
|
||||
|
||||
* Enable RuboCop and configure GitHub Actions to run RuboCop by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1185
|
||||
* Add Ruby 3.0.0 support by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1190
|
||||
* Drop Ruby 2.5 or older versions of Ruby by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1189
|
||||
* Move bug report templates into ransack repository and run templates at CI by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1191
|
||||
* Allow Ransack to be tested with Rails main branch by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1192
|
||||
|
||||
## 2.4.1 - 2020-12-21
|
||||
|
||||
* Add `ActiveRecord::Base.ransack!` which raises error if passed unknown condition
|
||||
|
||||
*Aaron Lipman*
|
||||
* Links to Tidelift subscription by @deivid-rodriguez in https://github.com/activerecord-hackery/ransack/pull/1178
|
||||
* Enable GitHub Actions by @yahonda in https://github.com/activerecord-hackery/ransack/pull/1180
|
||||
* Move security contact information to SECURITY.md by @deivid-rodriguez in https://github.com/activerecord-hackery/ransack/pull/1179
|
||||
* Add `ActiveRecord::Base.ransack!` which raises error if passed unknown condition by @alipman88 in https://github.com/activerecord-hackery/ransack/pull/1132
|
||||
* Add ability to config PostgreSQL ORDER BY ... NULLS FIRST or NULLS LAST by @itsalongstory in https://github.com/activerecord-hackery/ransack/pull/1184
|
||||
|
||||
## 2.4.0 - 2020-11-27
|
||||
|
||||
* Support ActiveRecord 6.1.0.rc1.
|
||||
PR [1172](https://github.com/activerecord-hackery/ransack/pull/1172)
|
||||
|
||||
* Fix for ActiveRecord 5.2.4 (note security fix in 5.2.4.2 for ActiveView's escape_javascript CVE-2020-5267 for all earlier versions)
|
||||
|
||||
* Drop support for ActiveRecord older than 5.2.4.
|
||||
PR [1166](https://github.com/activerecord-hackery/ransack/pull/1166)
|
||||
* Specify actual version of polyamorous, so we can release that separately by @gregmolnar in https://github.com/activerecord-hackery/ransack/pull/1101
|
||||
* Only include necessary files in gem package by @tvdeyen in https://github.com/activerecord-hackery/ransack/pull/1104
|
||||
* Test/Fix for subquery in Rails 5.2.4 by @stevenjonescgm in https://github.com/activerecord-hackery/ransack/pull/1112
|
||||
* Polyamorous module by @varyonic in https://github.com/activerecord-hackery/ransack/pull/1113
|
||||
* Remove duplicated rows by @sasharevzin in https://github.com/activerecord-hackery/ransack/pull/1116
|
||||
* Fix Ruby 2.7 deprecation warnings by @terracatta in https://github.com/activerecord-hackery/ransack/pull/1121
|
||||
* Fixes polymorphic joins. by @PhilCoggins in https://github.com/activerecord-hackery/ransack/pull/1122
|
||||
* Drop support for activerecord older than 5.2.4 by @deivid-rodriguez in https://github.com/activerecord-hackery/ransack/pull/1166
|
||||
* Adapt to quoting change in Rails by @deivid-rodriguez in https://github.com/activerecord-hackery/ransack/pull/1165
|
||||
* Typo in docs by @brett-anderson in https://github.com/activerecord-hackery/ransack/pull/1155
|
||||
* Add Rails 6.1 support by @deivid-rodriguez in https://github.com/activerecord-hackery/ransack/pull/1172
|
||||
* Strip Leading & Trailing Whitespace Before Searching by @itsalongstory in https://github.com/activerecord-hackery/ransack/pull/1126
|
||||
* Use unfrozen version of symbol to string by @fauno in https://github.com/activerecord-hackery/ransack/pull/1149
|
||||
|
||||
## 2.3.2 - 2020-01-11
|
||||
|
||||
|
@ -200,7 +261,7 @@
|
|||
ignored when block parameter is specified.
|
||||
PR [#818](https://github.com/activerecord-hackery/ransack/pull/818).
|
||||
|
||||
* No need pass some arugments to JoinAssociation#join_constraints in Rails 5.1.
|
||||
* No need pass some arguments to JoinAssociation#join_constraints in Rails 5.1.
|
||||
PR [#814](https://github.com/activerecord-hackery/ransack/pull/814).
|
||||
Fixes [#807](https://github.com/activerecord-hackery/ransack/issues/807).
|
||||
Reference [rails/rails#28267](https://github.com/rails/rails/pull/28267)
|
||||
|
|
|
@ -64,9 +64,7 @@ Here's a quick guide:
|
|||
2. Create a thoughtfully-named branch for your changes (`git checkout -b my-new-feature`).
|
||||
|
||||
3. Install the development dependencies by running `bundle install`.
|
||||
To install rails other than latest (set in Gemfile): `RAILS='5-2-stable' bundle install`
|
||||
|
||||
$ RAILS='5-2-stable' bundle install
|
||||
To install rails other than latest (set in Gemfile): `RAILS='6-0-stable' bundle install`
|
||||
|
||||
4. Begin by running the tests. We only take pull requests with passing tests,
|
||||
and it's great to know that you have a clean slate:
|
||||
|
|
91
README.md
91
README.md
|
@ -11,25 +11,22 @@ Ransack enables the creation of both
|
|||
for your Ruby on Rails application
|
||||
([demo source code here](https://github.com/activerecord-hackery/ransack_demo)).
|
||||
If you're looking for something that simplifies query generation at the model
|
||||
or controller layer, you're probably not looking for Ransack (or MetaSearch,
|
||||
for that matter). Try [Squeel](https://github.com/activerecord-hackery/squeel)
|
||||
instead.
|
||||
or controller layer, you're probably not looking for Ransack.
|
||||
|
||||
## Getting started
|
||||
|
||||
Ransack is supported for Rails 6.1, 6.0, 5.2 on Ruby 2.6.6 and later.
|
||||
Ransack is supported for Rails 7.0, 6.x on Ruby 2.6.6 and later.
|
||||
|
||||
In your Gemfile, for the last officially released gem:
|
||||
To install `ransack` and add it to your Gemfile, run
|
||||
|
||||
```ruby
|
||||
gem 'ransack'
|
||||
bundle add ransack
|
||||
```
|
||||
|
||||
If you would like to use the latest updates (recommended), use the `master`
|
||||
branch:
|
||||
If you would like to use the latest updates, use the `master` branch:
|
||||
|
||||
```ruby
|
||||
gem 'ransack', github: 'activerecord-hackery/ransack'
|
||||
bundle add ransack --github "activerecord-hackery/ransack"
|
||||
```
|
||||
|
||||
## Issues tracker
|
||||
|
@ -65,9 +62,6 @@ this example, with preloading each Person's Articles and pagination):
|
|||
def index
|
||||
@q = Person.ransack(params[:q])
|
||||
@people = @q.result.includes(:articles).page(params[:page])
|
||||
|
||||
# or use `to_a.uniq` to remove duplicates (can also be done in the view):
|
||||
@people = @q.result.includes(:articles).page(params[:page]).to_a.uniq
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -152,8 +146,11 @@ The `search_form_for` answer format can be set like this:
|
|||
```erb
|
||||
<%= sort_link(@q, :name) %>
|
||||
```
|
||||
Additional options can be passed after the column attribute, like a different
|
||||
column title or a default sort order:
|
||||
Additional options can be passed after the column parameter, like a different
|
||||
column title or a default sort order.
|
||||
|
||||
If the first option after the column parameter is a String, it's considered a
|
||||
custom label for the link:
|
||||
|
||||
```erb
|
||||
<%= sort_link(@q, :name, 'Last Name', default_order: :desc) %>
|
||||
|
@ -175,7 +172,8 @@ explicitly to avoid an `uninitialized constant Model::Xxxable` error (see issue
|
|||
<%= sort_link(@q, :xxxable_of_Ymodel_type_some_attribute, 'Attribute Name') %>
|
||||
```
|
||||
|
||||
You can also sort on multiple fields by specifying an ordered array:
|
||||
If the first option after the column parameter and/or the label parameter is an
|
||||
Array, it will be used for sorting on multiple fields:
|
||||
|
||||
```erb
|
||||
<%= sort_link(@q, :last_name, [:last_name, 'first_name asc'], 'Last Name') %>
|
||||
|
@ -185,7 +183,8 @@ In the example above, clicking the link will sort by `last_name` and then
|
|||
`first_name`. Specifying the sort direction on a field in the array tells
|
||||
Ransack to _always_ sort that particular field in the specified direction.
|
||||
|
||||
Multiple `default_order` fields may also be specified with a hash:
|
||||
Multiple `default_order` fields may also be specified with a trailing options
|
||||
Hash:
|
||||
|
||||
```erb
|
||||
<%= sort_link(@q, :last_name, %i(last_name first_name),
|
||||
|
@ -214,6 +213,9 @@ and you can then sort by this virtual field:
|
|||
<%= sort_link(@q, :reverse_name) %>
|
||||
```
|
||||
|
||||
The trailing options Hash can also be used for passing additional options to the
|
||||
generated link, like `class:`.
|
||||
|
||||
The sort link order indicator arrows may be globally customized by setting a
|
||||
`custom_arrows` option in an initializer file like
|
||||
`config/initializers/ransack.rb`.
|
||||
|
@ -278,11 +280,19 @@ Ransack.configure do |c|
|
|||
end
|
||||
```
|
||||
|
||||
To treat nulls as having the lowest or highest value respectively. To force nulls to always be first or last, use
|
||||
|
||||
```rb
|
||||
Ransack.configure do |c|
|
||||
c.postgres_fields_sort_option = :nulls_always_first # or :nulls_always_last
|
||||
end
|
||||
```
|
||||
|
||||
See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
||||
|
||||
#### Case Insensitive Sorting in PostgreSQL
|
||||
|
||||
In order to request PostgresSQL to do a case insensitive sort for all string columns of a model at once, Ransack can be extended by using this approach:
|
||||
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:
|
||||
|
||||
```ruby
|
||||
module RansackObject
|
||||
|
@ -307,7 +317,7 @@ end
|
|||
|
||||
If this approach is taken, it is advisable to [add a functional index](https://www.postgresql.org/docs/13/citext.html).
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
### Advanced Mode
|
||||
|
||||
|
@ -349,32 +359,6 @@ construct much more complex search forms, such as the one on the
|
|||
[demo app](http://ransack-demo.herokuapp.com/users/advanced_search)
|
||||
(source code [here](https://github.com/activerecord-hackery/ransack_demo)).
|
||||
|
||||
### Ransack #search method
|
||||
|
||||
Ransack will try to make the class method `#search` available in your
|
||||
models, but if `#search` has already been defined elsewhere, you can always use
|
||||
the default `#ransack` class method. So the following are equivalent:
|
||||
|
||||
```ruby
|
||||
Article.ransack(params[:q])
|
||||
Article.search(params[:q])
|
||||
```
|
||||
|
||||
Users have reported issues of `#search` name conflicts with other gems, so
|
||||
the `#search` method alias will be deprecated in the next major version of
|
||||
Ransack (2.0). It's advisable to use the default `#ransack` instead.
|
||||
|
||||
For now, if Ransack's `#search` method conflicts with the name of another
|
||||
method named `search` in your code or another gem, you may resolve it either by
|
||||
patching the `extended` class_method in `Ransack::Adapters::ActiveRecord::Base`
|
||||
to remove the line `alias :search :ransack unless base.respond_to? :search`, or
|
||||
by placing the following line in your Ransack initializer file at
|
||||
`config/initializers/ransack.rb`:
|
||||
|
||||
```ruby
|
||||
Ransack::Adapters::ActiveRecord::Base.class_eval('remove_method :search')
|
||||
```
|
||||
|
||||
### Associations
|
||||
|
||||
You can easily use Ransack to search for objects in `has_many` and `belongs_to`
|
||||
|
@ -467,6 +451,25 @@ query parameters in your URLs.
|
|||
<% end %>
|
||||
```
|
||||
|
||||
You can also use `ransack_alias` for sorting.
|
||||
|
||||
```ruby
|
||||
class Post < ActiveRecord::Base
|
||||
belongs_to :author
|
||||
|
||||
# Abbreviate :author_first_name to :author
|
||||
ransack_alias :author, :author_first_name
|
||||
end
|
||||
```
|
||||
|
||||
Now, you can use `:author` instead of `:author_first_name` in a `sort_link`.
|
||||
|
||||
```erb
|
||||
<%= sort_link(@q, :author) %>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Search Matchers
|
||||
|
||||
List of all possible predicates
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
module Polyamorous
|
||||
module JoinAssociationExtensions
|
||||
include SwappingReflectionClass
|
||||
def self.prepended(base)
|
||||
base.class_eval { attr_reader :join_type }
|
||||
end
|
||||
|
||||
def initialize(reflection, children, polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin)
|
||||
@join_type = join_type
|
||||
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
|
||||
swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
|
||||
super(reflection, children)
|
||||
self.reflection.options[:polymorphic] = true
|
||||
end
|
||||
else
|
||||
super(reflection, children)
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
base_klass == other.base_klass
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,79 +0,0 @@
|
|||
module Polyamorous
|
||||
module JoinDependencyExtensions
|
||||
# Replaces ActiveRecord::Associations::JoinDependency#build
|
||||
def build(associations, base_klass)
|
||||
associations.map do |name, right|
|
||||
if name.is_a? Join
|
||||
reflection = find_reflection base_klass, name.name
|
||||
reflection.check_validity!
|
||||
reflection.check_eager_loadable!
|
||||
|
||||
klass = if reflection.polymorphic?
|
||||
name.klass || base_klass
|
||||
else
|
||||
reflection.klass
|
||||
end
|
||||
JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
|
||||
else
|
||||
reflection = find_reflection base_klass, name
|
||||
reflection.check_validity!
|
||||
reflection.check_eager_loadable!
|
||||
|
||||
if reflection.polymorphic?
|
||||
raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
|
||||
end
|
||||
JoinAssociation.new(reflection, build(right, reflection.klass))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def join_constraints(joins_to_add, join_type, alias_tracker)
|
||||
@alias_tracker = alias_tracker
|
||||
|
||||
construct_tables!(join_root)
|
||||
joins = make_join_constraints(join_root, join_type)
|
||||
|
||||
joins.concat joins_to_add.flat_map { |oj|
|
||||
construct_tables!(oj.join_root)
|
||||
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
||||
walk join_root, oj.join_root
|
||||
else
|
||||
make_join_constraints(oj.join_root, join_type)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
||||
foreign_table = parent.table
|
||||
foreign_klass = parent.base_klass
|
||||
join_type = child.join_type || join_type if join_type == Arel::Nodes::InnerJoin
|
||||
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
||||
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
||||
#
|
||||
def walk_tree(associations, hash)
|
||||
case associations
|
||||
when TreeNode
|
||||
associations.add_to_tree(hash)
|
||||
when Hash
|
||||
associations.each do |k, v|
|
||||
cache =
|
||||
if TreeNode === k
|
||||
k.add_to_tree(hash)
|
||||
else
|
||||
hash[k] ||= {}
|
||||
end
|
||||
walk_tree(v, cache)
|
||||
end
|
||||
else
|
||||
super(associations, hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
module Polyamorous
|
||||
module ReflectionExtensions
|
||||
def join_scope(table, foreign_table, foreign_klass)
|
||||
if respond_to?(:polymorphic?) && polymorphic?
|
||||
super.where!(foreign_table[foreign_type].eq(klass.name))
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1 +1,20 @@
|
|||
require 'polyamorous/activerecord_5.2_ruby_2/join_association'
|
||||
module Polyamorous
|
||||
module JoinAssociationExtensions
|
||||
include SwappingReflectionClass
|
||||
def self.prepended(base)
|
||||
base.class_eval { attr_reader :join_type }
|
||||
end
|
||||
|
||||
def initialize(reflection, children, polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin)
|
||||
@join_type = join_type
|
||||
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
|
||||
swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
|
||||
super(reflection, children)
|
||||
self.reflection.options[:polymorphic] = true
|
||||
end
|
||||
else
|
||||
super(reflection, children)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# active_record_6.0_ruby_2/join_dependency.rb
|
||||
module Polyamorous
|
||||
module JoinDependencyExtensions
|
||||
# Replaces ActiveRecord::Associations::JoinDependency#build
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
require 'polyamorous/activerecord_5.2_ruby_2/reflection'
|
||||
module Polyamorous
|
||||
module ReflectionExtensions
|
||||
def join_scope(table, foreign_table, foreign_klass)
|
||||
if respond_to?(:polymorphic?) && polymorphic?
|
||||
super.where!(foreign_table[foreign_type].eq(klass.name))
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,9 +66,5 @@ module Polyamorous
|
|||
|
||||
joins
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
base_klass == other.base_klass
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# active_record_6.1_ruby_2/join_dependency.rb
|
||||
module Polyamorous
|
||||
module JoinDependencyExtensions
|
||||
# Replaces ActiveRecord::Associations::JoinDependency#build
|
||||
|
|
|
@ -4,7 +4,6 @@ module Ransack
|
|||
module Base
|
||||
|
||||
def self.extended(base)
|
||||
alias :search :ransack unless base.respond_to? :search
|
||||
base.class_eval do
|
||||
class_attribute :_ransackers
|
||||
class_attribute :_ransack_aliases
|
||||
|
@ -14,7 +13,6 @@ module Ransack
|
|||
end
|
||||
|
||||
def ransack(params = {}, options = {})
|
||||
ActiveSupport::Deprecation.warn("#search is deprecated and will be removed in 2.3, please use #ransack instead") if __callee__ == :search
|
||||
Search.new(self, params, options)
|
||||
end
|
||||
|
||||
|
@ -70,7 +68,7 @@ module Ransack
|
|||
end
|
||||
|
||||
# ransack_scope_skip_sanitize_args, by default, returns an empty array.
|
||||
# i.e. use the sanitize_scope_args setting to determin if args should be converted.
|
||||
# i.e. use the sanitize_scope_args setting to determine if args should be converted.
|
||||
# For overriding with a list of scopes which should be passed the args as-is.
|
||||
#
|
||||
def ransackable_scopes_skip_sanitize_args
|
||||
|
|
|
@ -47,6 +47,10 @@ module Ransack
|
|||
scope_or_sort = scope_or_sort.direction == :asc ? Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST") : Arel.sql("#{scope_or_sort.to_sql} NULLS LAST")
|
||||
when :nulls_last
|
||||
scope_or_sort = scope_or_sort.direction == :asc ? Arel.sql("#{scope_or_sort.to_sql} NULLS LAST") : Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST")
|
||||
when :nulls_always_first
|
||||
scope_or_sort = Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST")
|
||||
when :nulls_always_last
|
||||
scope_or_sort = Arel.sql("#{scope_or_sort.to_sql} NULLS LAST")
|
||||
end
|
||||
|
||||
relation = relation.order(scope_or_sort)
|
||||
|
|
|
@ -47,18 +47,19 @@ module Ransack
|
|||
end
|
||||
|
||||
def casted_array?(predicate)
|
||||
(predicate.respond_to?(:value) && predicate.value.is_a?(Array)) || # Rails 6.1
|
||||
(predicate.respond_to?(:val) && predicate.val.is_a?(Array)) # Rails 5.2, 6.0
|
||||
value_from(predicate).is_a?(Array) && predicate.is_a?(Arel::Nodes::Casted)
|
||||
end
|
||||
|
||||
def value_from(predicate)
|
||||
if predicate.respond_to?(:value)
|
||||
predicate.value # Rails 6.1
|
||||
elsif predicate.respond_to?(:val)
|
||||
predicate.val # Rails 6.0
|
||||
end
|
||||
end
|
||||
|
||||
def format_values_for(predicate)
|
||||
value = if predicate.respond_to?(:value)
|
||||
predicate.value # Rails 6.1
|
||||
else
|
||||
predicate.val # Rails 5.2, 6.0
|
||||
end
|
||||
|
||||
value.map do |val|
|
||||
value_from(predicate).map do |val|
|
||||
val.is_a?(String) ? Arel::Nodes.build_quoted(val) : val
|
||||
end
|
||||
end
|
||||
|
|
|
@ -149,7 +149,7 @@ module Ransack
|
|||
# User may want to configure it like this:
|
||||
#
|
||||
# Ransack.configure do |c|
|
||||
# c.postgres_fields_sort_option = :nulls_first # or :nulls_last
|
||||
# c.postgres_fields_sort_option = :nulls_first # or e.g. :nulls_always_last
|
||||
# end
|
||||
#
|
||||
# See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
||||
|
|
|
@ -130,12 +130,20 @@ module Ransack
|
|||
|
||||
def url_options
|
||||
@params.merge(
|
||||
@options.merge(
|
||||
@options.except(:class).merge(
|
||||
@search.context.search_key => search_and_sort_params))
|
||||
end
|
||||
|
||||
def html_options(args)
|
||||
html_options = extract_options_and_mutate_args!(args)
|
||||
if args.empty?
|
||||
html_options = @options
|
||||
else
|
||||
deprecation_message = "Passing two trailing hashes to `sort_link` is deprecated, merge the trailing hashes into a single one."
|
||||
caller_location = caller_locations(2, 2).first
|
||||
warn "#{deprecation_message} (called at #{caller_location.path}:#{caller_location.lineno})"
|
||||
html_options = extract_options_and_mutate_args!(args)
|
||||
end
|
||||
|
||||
html_options.merge(
|
||||
class: [['sort_link'.freeze, @current_dir], html_options[:class]]
|
||||
.compact.join(' '.freeze)
|
||||
|
@ -145,7 +153,7 @@ module Ransack
|
|||
private
|
||||
|
||||
def parameters_hash(params)
|
||||
if ::ActiveRecord::VERSION::MAJOR >= 5 && params.respond_to?(:to_unsafe_h)
|
||||
if params.respond_to?(:to_unsafe_h)
|
||||
params.to_unsafe_h
|
||||
else
|
||||
params
|
||||
|
|
|
@ -31,8 +31,8 @@ module Ransack
|
|||
end
|
||||
|
||||
def name=(name)
|
||||
@name = name
|
||||
context.bind(self, name)
|
||||
@name = context.ransackable_alias(name) || name
|
||||
context.bind(self, @name)
|
||||
end
|
||||
|
||||
def dir=(dir)
|
||||
|
|
|
@ -43,10 +43,10 @@ module Ransack
|
|||
collapse_multiparameter_attributes!(params).each do |key, value|
|
||||
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
|
||||
send("#{key}=", value)
|
||||
elsif base.attribute_method?(key)
|
||||
base.send("#{key}=", value)
|
||||
elsif @context.ransackable_scope?(key, @context.object)
|
||||
add_scope(key, value)
|
||||
elsif base.attribute_method?(key)
|
||||
base.send("#{key}=", value)
|
||||
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
||||
raise ArgumentError, "Invalid search term #{key}"
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Ransack
|
||||
VERSION = '2.4.2'
|
||||
VERSION = '2.6.0'
|
||||
end
|
||||
|
|
|
@ -15,8 +15,8 @@ Gem::Specification.new do |s|
|
|||
s.required_ruby_version = '>= 2.6'
|
||||
s.license = 'MIT'
|
||||
|
||||
s.add_dependency 'activerecord', '>= 5.2.4'
|
||||
s.add_dependency 'activesupport', '>= 5.2.4'
|
||||
s.add_dependency 'activerecord', '>= 6.0.4'
|
||||
s.add_dependency 'activesupport', '>= 6.0.4'
|
||||
s.add_dependency 'i18n'
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
|
|
15
spec/polyamorous/activerecord_compatibility_spec.rb
Normal file
15
spec/polyamorous/activerecord_compatibility_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Polyamorous
|
||||
describe "ActiveRecord Compatibility" do
|
||||
it 'works with self joins and includes' do
|
||||
trade_account = Account.create!
|
||||
Account.create!(trade_account: trade_account)
|
||||
|
||||
accounts = Account.joins(:trade_account).includes(:trade_account, :agent_account)
|
||||
account = accounts.first
|
||||
|
||||
expect(account.agent_account).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,12 +12,7 @@ module Polyamorous
|
|||
|
||||
subject { new_join_association(reflection, parent.children, Person) }
|
||||
|
||||
it 'respects polymorphism on equality test' do
|
||||
expect(subject).to eq new_join_association(reflection, parent.children, Person)
|
||||
expect(subject).not_to eq new_join_association(reflection, parent.children, Article)
|
||||
end
|
||||
|
||||
it 'leaves the orginal reflection intact for thread safety' do
|
||||
it 'leaves the original reflection intact for thread safety' do
|
||||
reflection.instance_variable_set(:@klass, Article)
|
||||
join_association
|
||||
.swapping_reflection_klass(reflection, Person) do |new_reflection|
|
||||
|
|
|
@ -77,21 +77,5 @@ module Polyamorous
|
|||
specify { expect(subject.send(:join_root).drop(1)[1].table_name)
|
||||
.to eq 'comments' }
|
||||
end
|
||||
|
||||
context '#left_outer_join in Rails 5 overrides join type specified',
|
||||
if: ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MAJOR < 6 && ActiveRecord::VERSION::MINOR < 2 do
|
||||
|
||||
let(:join_type_class) do
|
||||
new_join_dependency(
|
||||
Person,
|
||||
new_join(:articles)
|
||||
).join_constraints(
|
||||
[],
|
||||
Arel::Nodes::OuterJoin
|
||||
).first.joins.map(&:class)
|
||||
end
|
||||
|
||||
specify { expect(join_type_class).to eq [Arel::Nodes::OuterJoin] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,6 @@ module Ransack
|
|||
subject { ::ActiveRecord::Base }
|
||||
|
||||
it { should respond_to :ransack }
|
||||
it { should respond_to :search }
|
||||
|
||||
describe '#search' do
|
||||
subject { Person.ransack }
|
||||
|
@ -44,12 +43,12 @@ module Ransack
|
|||
|
||||
it 'applies stringy boolean scopes with true value in an array' do
|
||||
s = Person.ransack('of_age' => ['true'])
|
||||
expect(s.result.to_sql).to (include 'age >= 18')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{(age >= '18')} : 'age >= 18')
|
||||
end
|
||||
|
||||
it 'applies stringy boolean scopes with false value in an array' do
|
||||
s = Person.ransack('of_age' => ['false'])
|
||||
expect(s.result.to_sql).to (include 'age < 18')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age < '18'} : 'age < 18')
|
||||
end
|
||||
|
||||
it 'ignores unlisted scopes' do
|
||||
|
@ -69,12 +68,12 @@ module Ransack
|
|||
|
||||
it 'passes values to scopes' do
|
||||
s = Person.ransack('over_age' => 18)
|
||||
expect(s.result.to_sql).to (include 'age > 18')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
|
||||
end
|
||||
|
||||
it 'chains scopes' do
|
||||
s = Person.ransack('over_age' => 18, 'active' => true)
|
||||
expect(s.result.to_sql).to (include 'age > 18')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
|
||||
expect(s.result.to_sql).to (include 'active = 1')
|
||||
end
|
||||
|
||||
|
@ -99,12 +98,12 @@ module Ransack
|
|||
|
||||
it 'passes true values to scopes' do
|
||||
s = Person.ransack('over_age' => 1)
|
||||
expect(s.result.to_sql).to (include 'age > 1')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
|
||||
end
|
||||
|
||||
it 'passes false values to scopes' do
|
||||
s = Person.ransack('over_age' => 0)
|
||||
expect(s.result.to_sql).to (include 'age > 0')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -117,12 +116,12 @@ module Ransack
|
|||
|
||||
it 'passes true values to scopes' do
|
||||
s = Person.ransack('over_age' => 1)
|
||||
expect(s.result.to_sql).to (include 'age > 1')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
|
||||
end
|
||||
|
||||
it 'passes false values to scopes' do
|
||||
s = Person.ransack('over_age' => 0)
|
||||
expect(s.result.to_sql).to (include 'age > 0')
|
||||
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -324,7 +323,11 @@ module Ransack
|
|||
end
|
||||
|
||||
it 'should function correctly with a multi-parameter attribute' do
|
||||
::ActiveRecord::Base.default_timezone = :utc
|
||||
if ::ActiveRecord::VERSION::MAJOR >= 7
|
||||
::ActiveRecord.default_timezone = :utc
|
||||
else
|
||||
::ActiveRecord::Base.default_timezone = :utc
|
||||
end
|
||||
Time.zone = 'UTC'
|
||||
|
||||
date = Date.current
|
||||
|
@ -700,6 +703,10 @@ module Ransack
|
|||
it { should eq [] }
|
||||
end
|
||||
|
||||
private
|
||||
def rails7_and_mysql
|
||||
::ActiveRecord::VERSION::MAJOR >= 7 && ENV['DB'] == 'mysql'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -469,8 +469,7 @@ module Ransack
|
|||
it { should match /exist\=existing/ }
|
||||
end
|
||||
|
||||
context 'using a real ActionController::Parameter object',
|
||||
if: ::ActiveRecord::VERSION::MAJOR > 3 do
|
||||
context 'using a real ActionController::Parameter object' do
|
||||
|
||||
describe 'with symbol q:, #sort_link should include search params' do
|
||||
subject { @controller.view_context.sort_link(Person.ransack, :name) }
|
||||
|
@ -727,6 +726,38 @@ module Ransack
|
|||
it { should match /Block label ▼/ }
|
||||
end
|
||||
|
||||
describe '#sort_link with class option' do
|
||||
subject { @controller.view_context
|
||||
.sort_link(
|
||||
[:main_app, Person.ransack(sorts: ['name desc'])],
|
||||
:name,
|
||||
class: 'people', controller: 'people'
|
||||
)
|
||||
}
|
||||
it { should match /class="sort_link desc people"/ }
|
||||
it { should_not match /people\?class=people/ }
|
||||
end
|
||||
|
||||
describe '#sort_link with class option workaround' do
|
||||
it "generates a correct link and prints a deprecation" do
|
||||
expect do
|
||||
link = @controller.view_context
|
||||
.sort_link(
|
||||
[:main_app, Person.ransack(sorts: ['name desc'])],
|
||||
:name,
|
||||
'name',
|
||||
{ controller: 'people' },
|
||||
class: 'people'
|
||||
)
|
||||
|
||||
expect(link).to match(/class="sort_link desc people"/)
|
||||
expect(link).not_to match(/people\?class=people/)
|
||||
end.to output(
|
||||
/Passing two trailing hashes to `sort_link` is deprecated, merge the trailing hashes into a single one\. \(called at #{Regexp.escape(__FILE__)}:/
|
||||
).to_stderr
|
||||
end
|
||||
end
|
||||
|
||||
describe '#search_form_for with default format' do
|
||||
subject { @controller.view_context
|
||||
.search_form_for(Person.ransack) {} }
|
||||
|
|
|
@ -3,6 +3,19 @@ require 'spec_helper'
|
|||
module Ransack
|
||||
module Nodes
|
||||
describe Condition do
|
||||
context 'bug report #1245' do
|
||||
it 'preserves tuple behavior' do
|
||||
ransack_hash = {
|
||||
m: 'and',
|
||||
g: [
|
||||
{ title_type_in: ['["title 1", ""]'] }
|
||||
]
|
||||
}
|
||||
|
||||
sql = Article.ransack(ransack_hash).result.to_sql
|
||||
expect(sql).to include("IN (('title 1', ''))")
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an alias' do
|
||||
subject {
|
||||
|
|
|
@ -312,6 +312,29 @@ module Ransack
|
|||
expect { Search.new(Person, params) }.not_to change { params }
|
||||
end
|
||||
|
||||
context "ransackable_scope" do
|
||||
around(:each) do |example|
|
||||
Person.define_singleton_method(:name_eq) do |name|
|
||||
self.where(name: name)
|
||||
end
|
||||
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
Person.singleton_class.undef_method :name_eq
|
||||
end
|
||||
end
|
||||
|
||||
it "is prioritized over base predicates" do
|
||||
allow(Person).to receive(:ransackable_scopes)
|
||||
.and_return(Person.ransackable_scopes + [:name_eq])
|
||||
|
||||
s = Search.new(Person, name_eq: "Johny")
|
||||
expect(s.instance_variable_get(:@scope_args)["name_eq"]).to eq("Johny")
|
||||
expect(s.base[:name_eq]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#result' do
|
||||
|
@ -332,8 +355,6 @@ module Ransack
|
|||
end
|
||||
|
||||
it 'use appropriate table alias' do
|
||||
skip "Rails 6 regressed here, but it's fixed in 6-0-stable since https://github.com/rails/rails/commit/f9ba52477ca288e7effa5f6794ae3df3f4e982bc" if ENV["RAILS"] == "v6.0.3"
|
||||
|
||||
s = Search.new(Person, {
|
||||
name_eq: "person_name_query",
|
||||
articles_title_eq: "person_article_title_query",
|
||||
|
@ -483,82 +504,109 @@ module Ransack
|
|||
expect(sort.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes/directions in array format' do
|
||||
@s.sorts = ['id desc', { name: 'name', dir: 'asc' }]
|
||||
it 'creates sorts based on a single alias/direction' do
|
||||
@s.sorts = 'daddy desc'
|
||||
expect(@s.sorts.size).to eq(1)
|
||||
sort = @s.sorts.first
|
||||
expect(sort).to be_a Nodes::Sort
|
||||
expect(sort.name).to eq 'parent_name'
|
||||
expect(sort.dir).to eq 'desc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on a single alias and uppercase direction' do
|
||||
@s.sorts = 'daddy DESC'
|
||||
expect(@s.sorts.size).to eq(1)
|
||||
sort = @s.sorts.first
|
||||
expect(sort).to be_a Nodes::Sort
|
||||
expect(sort.name).to eq 'parent_name'
|
||||
expect(sort.dir).to eq 'desc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on a single alias and without direction' do
|
||||
@s.sorts = 'daddy'
|
||||
expect(@s.sorts.size).to eq(1)
|
||||
sort = @s.sorts.first
|
||||
expect(sort).to be_a Nodes::Sort
|
||||
expect(sort.name).to eq 'parent_name'
|
||||
expect(sort.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on attributes, alias and directions in array format' do
|
||||
@s.sorts = ['id desc', { name: 'daddy', dir: 'asc' }]
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
sort1, sort2 = @s.sorts
|
||||
expect(sort1).to be_a Nodes::Sort
|
||||
expect(sort1.name).to eq 'id'
|
||||
expect(sort1.dir).to eq 'desc'
|
||||
expect(sort2).to be_a Nodes::Sort
|
||||
expect(sort2.name).to eq 'name'
|
||||
expect(sort2.name).to eq 'parent_name'
|
||||
expect(sort2.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes and uppercase directions in array format' do
|
||||
@s.sorts = ['id DESC', { name: 'name', dir: 'ASC' }]
|
||||
it 'creates sorts based on attributes, alias and uppercase directions in array format' do
|
||||
@s.sorts = ['id DESC', { name: 'daddy', dir: 'ASC' }]
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
sort1, sort2 = @s.sorts
|
||||
expect(sort1).to be_a Nodes::Sort
|
||||
expect(sort1.name).to eq 'id'
|
||||
expect(sort1.dir).to eq 'desc'
|
||||
expect(sort2).to be_a Nodes::Sort
|
||||
expect(sort2.name).to eq 'name'
|
||||
expect(sort2.name).to eq 'parent_name'
|
||||
expect(sort2.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes and different directions
|
||||
it 'creates sorts based on attributes, alias and different directions
|
||||
in array format' do
|
||||
@s.sorts = ['id DESC', { name: 'name', dir: nil }]
|
||||
@s.sorts = ['id DESC', { name: 'daddy', dir: nil }]
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
sort1, sort2 = @s.sorts
|
||||
expect(sort1).to be_a Nodes::Sort
|
||||
expect(sort1.name).to eq 'id'
|
||||
expect(sort1.dir).to eq 'desc'
|
||||
expect(sort2).to be_a Nodes::Sort
|
||||
expect(sort2.name).to eq 'name'
|
||||
expect(sort2.name).to eq 'parent_name'
|
||||
expect(sort2.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes/directions in hash format' do
|
||||
it 'creates sorts based on attributes, alias and directions in hash format' do
|
||||
@s.sorts = {
|
||||
'0' => { name: 'id', dir: 'desc' },
|
||||
'1' => { name: 'name', dir: 'asc' }
|
||||
'1' => { name: 'daddy', dir: 'asc' }
|
||||
}
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
||||
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
||||
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
||||
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
||||
expect(id_sort.dir).to eq 'desc'
|
||||
expect(name_sort.dir).to eq 'asc'
|
||||
expect(daddy_sort.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes and uppercase directions
|
||||
it 'creates sorts based on attributes, alias and uppercase directions
|
||||
in hash format' do
|
||||
@s.sorts = {
|
||||
'0' => { name: 'id', dir: 'DESC' },
|
||||
'1' => { name: 'name', dir: 'ASC' }
|
||||
'1' => { name: 'daddy', dir: 'ASC' }
|
||||
}
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
||||
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
||||
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
||||
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
||||
expect(id_sort.dir).to eq 'desc'
|
||||
expect(name_sort.dir).to eq 'asc'
|
||||
expect(daddy_sort.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'creates sorts based on multiple attributes and different directions
|
||||
it 'creates sorts based on attributes, alias and different directions
|
||||
in hash format' do
|
||||
@s.sorts = {
|
||||
'0' => { name: 'id', dir: 'DESC' },
|
||||
'1' => { name: 'name', dir: nil }
|
||||
'1' => { name: 'daddy', dir: nil }
|
||||
}
|
||||
expect(@s.sorts.size).to eq(2)
|
||||
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
||||
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
||||
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
||||
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
||||
expect(id_sort.dir).to eq 'desc'
|
||||
expect(name_sort.dir).to eq 'asc'
|
||||
expect(daddy_sort.dir).to eq 'asc'
|
||||
end
|
||||
|
||||
it 'overrides existing sort' do
|
||||
|
@ -605,6 +653,18 @@ module Ransack
|
|||
s = Search.new(Person, s: 'doubled_name desc')
|
||||
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
||||
|
||||
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_first }
|
||||
s = Search.new(Person, s: 'doubled_name asc')
|
||||
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS FIRST"
|
||||
s = Search.new(Person, s: 'doubled_name desc')
|
||||
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
||||
|
||||
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_last }
|
||||
s = Search.new(Person, s: 'doubled_name asc')
|
||||
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS LAST"
|
||||
s = Search.new(Person, s: 'doubled_name desc')
|
||||
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS LAST"
|
||||
|
||||
Ransack.options = default
|
||||
end
|
||||
end
|
||||
|
|
|
@ -154,6 +154,29 @@ class Article < ActiveRecord::Base
|
|||
|
||||
joins(join).where("latest_comment.body ILIKE ?", "%#{msg}%")
|
||||
}
|
||||
|
||||
ransacker :title_type, formatter: lambda { |tuples|
|
||||
title, type = JSON.parse(tuples)
|
||||
Arel::Nodes::Grouping.new(
|
||||
[
|
||||
Arel::Nodes.build_quoted(title),
|
||||
Arel::Nodes.build_quoted(type)
|
||||
]
|
||||
)
|
||||
} do |_parent|
|
||||
articles = Article.arel_table
|
||||
Arel::Nodes::Grouping.new(
|
||||
%i[title type].map do |field|
|
||||
Arel::Nodes::NamedFunction.new(
|
||||
'COALESCE',
|
||||
[
|
||||
Arel::Nodes::NamedFunction.new('TRIM', [articles[field]]),
|
||||
Arel::Nodes.build_quoted('')
|
||||
]
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class StoryArticle < Article
|
||||
|
@ -192,6 +215,11 @@ class Note < ActiveRecord::Base
|
|||
belongs_to :notable, polymorphic: true
|
||||
end
|
||||
|
||||
class Account < ActiveRecord::Base
|
||||
belongs_to :agent_account, class_name: "Account"
|
||||
belongs_to :trade_account, class_name: "Account"
|
||||
end
|
||||
|
||||
module Schema
|
||||
def self.create
|
||||
ActiveRecord::Migration.verbose = false
|
||||
|
@ -250,6 +278,11 @@ module Schema
|
|||
t.integer :target_person_id
|
||||
t.integer :article_id
|
||||
end
|
||||
|
||||
create_table :accounts, force: true do |t|
|
||||
t.belongs_to :agent_account
|
||||
t.belongs_to :trade_account
|
||||
end
|
||||
end
|
||||
|
||||
10.times do
|
||||
|
|
Loading…
Reference in a new issue