ransack 2.4.0 → 2.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/cronjob.yml +105 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test.yml +154 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +8 -3
- data/CONTRIBUTING.md +2 -5
- data/Gemfile +4 -2
- data/README.md +95 -25
- 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 +20 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/polyamorous.rb +1 -1
- data/lib/ransack.rb +2 -2
- data/lib/ransack/adapters/active_record/base.rb +4 -0
- data/lib/ransack/adapters/active_record/context.rb +10 -3
- data/lib/ransack/adapters/active_record/ransack/constants.rb +1 -1
- data/lib/ransack/configuration.rb +17 -1
- data/lib/ransack/constants.rb +2 -3
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/helpers/form_builder.rb +3 -3
- data/lib/ransack/nodes/attribute.rb +1 -1
- data/lib/ransack/nodes/condition.rb +0 -2
- data/lib/ransack/nodes/sort.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/search.rb +2 -1
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +4 -3
- 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/ransack_helper.rb +1 -1
- data/spec/ransack/adapters/active_record/base_spec.rb +6 -3
- data/spec/ransack/adapters/active_record/context_spec.rb +1 -2
- data/spec/ransack/configuration_spec.rb +10 -0
- data/spec/ransack/helpers/form_helper_spec.rb +16 -16
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/predicate_spec.rb +1 -1
- data/spec/ransack/search_spec.rb +49 -2
- data/spec/spec_helper.rb +7 -6
- data/spec/support/schema.rb +2 -2
- metadata +16 -4
- data/.travis.yml +0 -47
@@ -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,20 @@
|
|
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
|
+
<<<<<<< Updated upstream
|
9
|
+
- Update the versions file to the new release, commit and push to `master`.
|
10
|
+
=======
|
11
|
+
- Update the [version.rb](../lib/ransack/version.rb) file to the new release, commit and push to `master`.
|
12
|
+
>>>>>>> Stashed changes
|
13
|
+
- From the terminal, run the following commands
|
14
|
+
|
15
|
+
```bash
|
16
|
+
rake build
|
17
|
+
rake release
|
18
|
+
```
|
19
|
+
|
20
|
+
![Create a Release](img/create_release.png)
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/join_association'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/join_dependency'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/reflection'
|
@@ -11,7 +11,7 @@ if defined?(::ActiveRecord)
|
|
11
11
|
require 'polyamorous/join'
|
12
12
|
require 'polyamorous/swapping_reflection_class'
|
13
13
|
|
14
|
-
ar_version = ::ActiveRecord::VERSION::STRING[0,3]
|
14
|
+
ar_version = ::ActiveRecord::VERSION::STRING[0, 3]
|
15
15
|
%w(join_association join_dependency reflection).each do |file|
|
16
16
|
require "polyamorous/activerecord_#{ar_version}_ruby_2/#{file}"
|
17
17
|
end
|
data/lib/ransack.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
2
|
require 'ransack/configuration'
|
3
3
|
require 'ransack/adapters'
|
4
|
-
require 'polyamorous/polyamorous
|
4
|
+
require 'polyamorous/polyamorous'
|
5
5
|
|
6
6
|
Ransack::Adapters.object_mapper.require_constants
|
7
7
|
|
8
8
|
module Ransack
|
9
9
|
extend Configuration
|
10
|
-
class UntraversableAssociationError < StandardError; end
|
10
|
+
class UntraversableAssociationError < StandardError; end
|
11
11
|
end
|
12
12
|
|
13
13
|
Ransack.configure do |config|
|
@@ -18,6 +18,10 @@ module Ransack
|
|
18
18
|
Search.new(self, params, options)
|
19
19
|
end
|
20
20
|
|
21
|
+
def ransack!(params = {}, options = {})
|
22
|
+
ransack(params, options.merge(ignore_unknown_conditions: false))
|
23
|
+
end
|
24
|
+
|
21
25
|
def ransacker(name, opts = {}, &block)
|
22
26
|
self._ransackers = _ransackers.merge name.to_s => Ransacker
|
23
27
|
.new(self, name, opts, &block)
|
@@ -42,6 +42,13 @@ module Ransack
|
|
42
42
|
if scope_or_sort.is_a?(Symbol)
|
43
43
|
relation = relation.send(scope_or_sort)
|
44
44
|
else
|
45
|
+
case Ransack.options[:postgres_fields_sort_option]
|
46
|
+
when :nulls_first
|
47
|
+
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS FIRST" : "#{scope_or_sort.to_sql} NULLS LAST"
|
48
|
+
when :nulls_last
|
49
|
+
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS LAST" : "#{scope_or_sort.to_sql} NULLS FIRST"
|
50
|
+
end
|
51
|
+
|
45
52
|
relation = relation.order(scope_or_sort)
|
46
53
|
end
|
47
54
|
end
|
@@ -99,7 +106,7 @@ module Ransack
|
|
99
106
|
def join_sources
|
100
107
|
base, joins = begin
|
101
108
|
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, @object.table.name, [])
|
102
|
-
constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::
|
109
|
+
constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
103
110
|
@join_dependency.join_constraints(@object.joins_values, alias_tracker, @object.references_values)
|
104
111
|
elsif ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_0)
|
105
112
|
@join_dependency.join_constraints(@object.joins_values, alias_tracker)
|
@@ -327,7 +334,7 @@ module Ransack
|
|
327
334
|
@join_dependency.instance_variable_get(:@join_root).children.push found_association
|
328
335
|
|
329
336
|
# Builds the arel nodes properly for this association
|
330
|
-
if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::
|
337
|
+
if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
331
338
|
@tables_pot[found_association] = @join_dependency.construct_tables_for_association!(jd.instance_variable_get(:@join_root), found_association)
|
332
339
|
else
|
333
340
|
@join_dependency.send(:construct_tables!, jd.instance_variable_get(:@join_root))
|
@@ -341,7 +348,7 @@ module Ransack
|
|
341
348
|
def extract_joins(association)
|
342
349
|
parent = @join_dependency.instance_variable_get(:@join_root)
|
343
350
|
reflection = association.reflection
|
344
|
-
join_constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::
|
351
|
+
join_constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
345
352
|
association.join_constraints_with_tables(
|
346
353
|
parent.table,
|
347
354
|
parent.base_klass,
|
@@ -97,7 +97,7 @@ module Ransack
|
|
97
97
|
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
98
98
|
compounds: false,
|
99
99
|
type: :boolean,
|
100
|
-
validator: proc { |v| BOOLEAN_VALUES.include?(v)},
|
100
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
101
101
|
formatter: proc { |v| nil }
|
102
102
|
}
|
103
103
|
],
|
@@ -33,7 +33,8 @@ module Ransack
|
|
33
33
|
:up_arrow => '▼'.freeze,
|
34
34
|
:down_arrow => '▲'.freeze,
|
35
35
|
:default_arrow => nil,
|
36
|
-
:sanitize_scope_args => true
|
36
|
+
:sanitize_scope_args => true,
|
37
|
+
:postgres_fields_sort_option => nil
|
37
38
|
}
|
38
39
|
|
39
40
|
def configure
|
@@ -141,6 +142,21 @@ module Ransack
|
|
141
142
|
self.options[:sanitize_scope_args] = boolean
|
142
143
|
end
|
143
144
|
|
145
|
+
# The `NULLS FIRST` and `NULLS LAST` options can be used to determine
|
146
|
+
# whether nulls appear before or after non-null values in the sort ordering.
|
147
|
+
#
|
148
|
+
# User may want to configure it like this:
|
149
|
+
#
|
150
|
+
# Ransack.configure do |c|
|
151
|
+
# c.postgres_fields_sort_option = :nulls_first # or :nulls_last
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
155
|
+
#
|
156
|
+
def postgres_fields_sort_option=(setting)
|
157
|
+
self.options[:postgres_fields_sort_option] = setting
|
158
|
+
end
|
159
|
+
|
144
160
|
# By default, Ransack displays sort order indicator arrows in sort links.
|
145
161
|
# The default may be globally overridden in an initializer file like
|
146
162
|
# `config/initializers/ransack.rb` as follows:
|
data/lib/ransack/constants.rb
CHANGED
@@ -36,7 +36,7 @@ module Ransack
|
|
36
36
|
'lt'.freeze, 'lteq'.freeze,
|
37
37
|
'gt'.freeze, 'gteq'.freeze,
|
38
38
|
'in'.freeze, 'not_in'.freeze
|
39
|
-
|
39
|
+
].freeze
|
40
40
|
A_S_I = ['a'.freeze, 's'.freeze, 'i'.freeze].freeze
|
41
41
|
|
42
42
|
EQ = 'eq'.freeze
|
@@ -46,10 +46,9 @@ module Ransack
|
|
46
46
|
CONT = 'cont'.freeze
|
47
47
|
|
48
48
|
RAILS_6_0 = '6.0.0'.freeze
|
49
|
-
|
49
|
+
RAILS_6_1 = '6.1.0'.freeze
|
50
50
|
|
51
51
|
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
52
52
|
RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
data/lib/ransack/helpers.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'ransack/helpers/form_builder'
|
2
|
-
require 'ransack/helpers/form_helper'
|
2
|
+
require 'ransack/helpers/form_helper'
|
@@ -45,9 +45,9 @@ module Ransack
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def attribute_select(options = nil, html_options = nil, action = nil)
|
48
|
-
options
|
49
|
-
html_options
|
50
|
-
action
|
48
|
+
options ||= {}
|
49
|
+
html_options ||= {}
|
50
|
+
action ||= Constants::SEARCH
|
51
51
|
default = options.delete(:default)
|
52
52
|
raise ArgumentError, formbuilder_error_message(
|
53
53
|
"#{action}_select") unless object.respond_to?(:context)
|
@@ -127,7 +127,6 @@ module Ransack
|
|
127
127
|
alias :m= :combinator=
|
128
128
|
alias :m :combinator
|
129
129
|
|
130
|
-
|
131
130
|
# == build_attribute
|
132
131
|
#
|
133
132
|
# This method was originally called from Nodes::Grouping#new_condition
|
@@ -263,7 +262,6 @@ module Ransack
|
|
263
262
|
attr.attr
|
264
263
|
end
|
265
264
|
|
266
|
-
|
267
265
|
def default_type
|
268
266
|
predicate.type || (attributes.first && attributes.first.type)
|
269
267
|
end
|
data/lib/ransack/nodes/sort.rb
CHANGED
data/lib/ransack/nodes/value.rb
CHANGED
data/lib/ransack/search.rb
CHANGED
@@ -30,6 +30,7 @@ module Ransack
|
|
30
30
|
)
|
31
31
|
@scope_args = {}
|
32
32
|
@sorts ||= []
|
33
|
+
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
|
33
34
|
build(params.with_indifferent_access)
|
34
35
|
end
|
35
36
|
|
@@ -45,7 +46,7 @@ module Ransack
|
|
45
46
|
base.send("#{key}=", value)
|
46
47
|
elsif @context.ransackable_scope?(key, @context.object)
|
47
48
|
add_scope(key, value)
|
48
|
-
elsif !Ransack.options[:ignore_unknown_conditions]
|
49
|
+
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
49
50
|
raise ArgumentError, "Invalid search term #{key}"
|
50
51
|
end
|
51
52
|
end
|
data/lib/ransack/version.rb
CHANGED
data/ransack.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
|
2
3
|
$:.push File.expand_path("../lib", __FILE__)
|
3
4
|
require "ransack/version"
|
4
5
|
|
@@ -6,12 +7,12 @@ Gem::Specification.new do |s|
|
|
6
7
|
s.name = "ransack"
|
7
8
|
s.version = Ransack::VERSION
|
8
9
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack","Sean Carroll"]
|
10
|
-
s.email = ["ernie@erniemiller.org", "radarlistener@gmail.com", "jonnyatack@gmail.com","sfcarroll@gmail.com"]
|
10
|
+
s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack", "Sean Carroll"]
|
11
|
+
s.email = ["ernie@erniemiller.org", "radarlistener@gmail.com", "jonnyatack@gmail.com", "sfcarroll@gmail.com"]
|
11
12
|
s.homepage = "https://github.com/activerecord-hackery/ransack"
|
12
13
|
s.summary = %q{Object-based searching for Active Record and Mongoid (currently).}
|
13
14
|
s.description = %q{Ransack is the successor to the MetaSearch gem. It improves and expands upon MetaSearch's functionality, but does not have a 100%-compatible API.}
|
14
|
-
s.required_ruby_version = '>= 2.
|
15
|
+
s.required_ruby_version = '>= 2.6'
|
15
16
|
s.license = 'MIT'
|
16
17
|
|
17
18
|
s.add_dependency 'activerecord', '>= 5.2.4'
|
data/spec/blueprints/articles.rb
CHANGED