ransack 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +12 -4
- data/CONTRIBUTING.md +10 -4
- data/Gemfile +12 -9
- data/README.md +46 -11
- data/lib/ransack.rb +4 -2
- data/lib/ransack/adapters/active_record.rb +1 -1
- data/lib/ransack/adapters/active_record/3.0/compat.rb +16 -6
- data/lib/ransack/adapters/active_record/3.0/context.rb +32 -16
- data/lib/ransack/adapters/active_record/3.1/context.rb +32 -15
- data/lib/ransack/adapters/active_record/3.2/context.rb +1 -1
- data/lib/ransack/adapters/active_record/base.rb +9 -6
- data/lib/ransack/adapters/active_record/context.rb +193 -2
- data/lib/ransack/configuration.rb +4 -4
- data/lib/ransack/constants.rb +81 -18
- data/lib/ransack/context.rb +27 -12
- data/lib/ransack/helpers/form_builder.rb +126 -91
- data/lib/ransack/helpers/form_helper.rb +34 -12
- data/lib/ransack/naming.rb +2 -1
- data/lib/ransack/nodes/attribute.rb +6 -4
- data/lib/ransack/nodes/bindable.rb +3 -1
- data/lib/ransack/nodes/condition.rb +40 -27
- data/lib/ransack/nodes/grouping.rb +19 -13
- data/lib/ransack/nodes/node.rb +3 -3
- data/lib/ransack/nodes/sort.rb +5 -3
- data/lib/ransack/nodes/value.rb +2 -2
- data/lib/ransack/predicate.rb +18 -9
- data/lib/ransack/ransacker.rb +4 -4
- data/lib/ransack/search.rb +9 -12
- data/lib/ransack/translate.rb +42 -21
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +4 -4
- data/ransack.gemspec +17 -7
- data/spec/blueprints/notes.rb +2 -0
- data/spec/blueprints/people.rb +4 -1
- data/spec/console.rb +3 -3
- data/spec/ransack/adapters/active_record/base_spec.rb +149 -22
- data/spec/ransack/adapters/active_record/context_spec.rb +5 -5
- data/spec/ransack/configuration_spec.rb +17 -8
- data/spec/ransack/dependencies_spec.rb +8 -0
- data/spec/ransack/helpers/form_builder_spec.rb +37 -14
- data/spec/ransack/helpers/form_helper_spec.rb +5 -5
- data/spec/ransack/predicate_spec.rb +6 -3
- data/spec/ransack/search_spec.rb +95 -73
- data/spec/ransack/translate_spec.rb +14 -0
- data/spec/spec_helper.rb +14 -8
- data/spec/support/en.yml +6 -0
- data/spec/support/schema.rb +76 -31
- metadata +48 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b7aa5bc2bb1d2e9d78aea7431f3f3124b09ffdb
|
4
|
+
data.tar.gz: f16d483b98b63bd8d427678a185cb8ce7e6e56a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03ca0f504276420d2bc2f3ed1b2e2685091043f01fac0bcf538802d8ddae0ba6ee8c4fc36224d12aaf955beb3f709581dd7a207ef9b98a4eb10af136c0c38f2f
|
7
|
+
data.tar.gz: f77643a092da8bc3119b4f85d8cdc90977df7b78fc8738b3c0a490d18a21c492bed5e84df349bf4d3214016783c32ae07a82f14ea48435d94abbc63774af72b8
|
data/.travis.yml
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
before_install:
|
4
|
+
- travis_retry gem install bundler
|
5
|
+
|
1
6
|
rvm:
|
2
|
-
- 1.9.3
|
3
7
|
- 2.0.0
|
4
8
|
|
5
9
|
env:
|
6
|
-
-
|
10
|
+
- RAILS=4-1-stable DB=sqlite3
|
11
|
+
- RAILS=4-1-stable DB=mysql
|
12
|
+
- RAILS=4-1-stable DB=postgres
|
13
|
+
- RAILS=4-0-stable DB=sqlite3
|
7
14
|
- RAILS=4-0-stable DB=mysql
|
8
15
|
- RAILS=4-0-stable DB=postgres
|
9
16
|
- RAILS=3-2-stable DB=sqlite
|
@@ -17,5 +24,6 @@ env:
|
|
17
24
|
- RAILS=3-0-stable DB=postgres
|
18
25
|
|
19
26
|
before_script:
|
20
|
-
- mysql -e 'create database ransack;'
|
21
|
-
-
|
27
|
+
- mysql -e 'create database ransack collate utf8_general_ci;'
|
28
|
+
- mysql -e 'use ransack;show variables like "%character%";show variables like "%collation%";'
|
29
|
+
- psql -c 'create database ransack;' -U postgres
|
data/CONTRIBUTING.md
CHANGED
@@ -8,13 +8,17 @@ When filing an issue on the Ransack project, please provide these details:
|
|
8
8
|
* The version of Ransack *and* the version of Rails.
|
9
9
|
* Any relevant stack traces ("Full trace" preferred)
|
10
10
|
|
11
|
-
In 99% of cases, this information is enough to determine the cause and
|
11
|
+
In 99% of cases, this information is enough to determine the cause and
|
12
|
+
solution to the problem that is being described.
|
12
13
|
|
13
|
-
Any issue that is open for 14 days without actionable information or activity
|
14
|
+
Any issue that is open for 14 days without actionable information or activity
|
15
|
+
will be marked as "stalled" and then closed. Stalled issues can be re-opened
|
16
|
+
if the information requested is provided.
|
14
17
|
|
15
18
|
## Pull requests
|
16
19
|
|
17
|
-
We gladly accept pull requests to fix bugs and, in some circumstances, add new
|
20
|
+
We gladly accept pull requests to fix bugs and, in some circumstances, add new
|
21
|
+
features to Ransack.
|
18
22
|
|
19
23
|
Here's a quick guide:
|
20
24
|
|
@@ -32,7 +36,9 @@ a test!
|
|
32
36
|
|
33
37
|
4. Make the test pass.
|
34
38
|
|
35
|
-
5. Push to your fork and submit a pull request. If the changes will apply
|
39
|
+
5. Push to your fork and submit a pull request. If the changes will apply
|
40
|
+
cleanly to the latest stable branches and master branch, you will only need
|
41
|
+
to submit one pull request.
|
36
42
|
|
37
43
|
At this point you're waiting on us. We like to at least comment on, if not
|
38
44
|
accept, pull requests within three business days (and, typically, one business
|
data/Gemfile
CHANGED
@@ -1,30 +1,33 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
3
3
|
|
4
4
|
gem 'rake'
|
5
5
|
|
6
|
-
rails = ENV['RAILS'] || '
|
6
|
+
rails = ENV['RAILS'] || 'master'
|
7
7
|
|
8
|
-
gem '
|
8
|
+
gem 'polyamorous', github: 'activerecord-hackery/polyamorous'
|
9
9
|
|
10
10
|
case rails
|
11
11
|
when /\// # A path
|
12
|
-
gem 'activesupport', :
|
13
|
-
gem 'activemodel', :
|
14
|
-
gem 'activerecord', :
|
15
|
-
gem 'actionpack', :
|
12
|
+
gem 'activesupport', path: "#{rails}/activesupport"
|
13
|
+
gem 'activemodel', path: "#{rails}/activemodel"
|
14
|
+
gem 'activerecord', path: "#{rails}/activerecord"
|
15
|
+
gem 'actionpack', path: "#{rails}/activerecord"
|
16
16
|
when /^v/ # A tagged version
|
17
|
-
git 'git://github.com/rails/rails.git', :
|
17
|
+
git 'git://github.com/rails/rails.git', tag: rails do
|
18
18
|
gem 'activesupport'
|
19
19
|
gem 'activemodel'
|
20
20
|
gem 'activerecord'
|
21
21
|
gem 'actionpack'
|
22
22
|
end
|
23
23
|
else
|
24
|
-
git 'git://github.com/rails/rails.git', :
|
24
|
+
git 'git://github.com/rails/rails.git', branch: rails do
|
25
25
|
gem 'activesupport'
|
26
26
|
gem 'activemodel'
|
27
27
|
gem 'activerecord'
|
28
28
|
gem 'actionpack'
|
29
29
|
end
|
30
|
+
if rails == '3-0-stable'
|
31
|
+
gem 'mysql2', '< 0.3'
|
32
|
+
end
|
30
33
|
end
|
data/README.md
CHANGED
@@ -1,29 +1,42 @@
|
|
1
1
|
# Ransack
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/
|
3
|
+
[![Build Status](https://travis-ci.org/activerecord-hackery/ransack.svg)](https://travis-ci.org/activerecord-hackery/ransack)
|
4
4
|
|
5
|
-
Ransack is a rewrite of [MetaSearch](https://github.com/
|
5
|
+
Ransack is a rewrite of [MetaSearch](https://github.com/activerecord-hackery/meta_search) created by [Ernie Miller](http://twitter.com/erniemiller) and maintained by [Ryan Bigg](http://twitter.com/ryanbigg), [Jon Atack](http://twitter.com/jonatack) and a great group of [contributors](https://github.com/activerecord-hackery/ransack/graphs/contributors). While it
|
6
6
|
supports many of the same features as MetaSearch, its underlying implementation differs
|
7
7
|
greatly from MetaSearch, and _backwards compatibility is not a design goal._
|
8
8
|
|
9
9
|
Ransack enables the creation of both simple and [advanced](http://ransack-demo.herokuapp.com/users/advanced_search)
|
10
|
-
search forms against your application's models. If you're looking for something that
|
10
|
+
search forms against your application's models (demo source code [here](https://github.com/activerecord-hackery/ransack_demo)). If you're looking for something that
|
11
11
|
simplifies query generation at the model or controller layer, you're probably not looking
|
12
12
|
for Ransack (or MetaSearch, for that matter). Try
|
13
|
-
[Squeel](https://github.com/
|
13
|
+
[Squeel](https://github.com/activerecord-hackery/squeel) instead.
|
14
14
|
|
15
15
|
## Getting started
|
16
16
|
|
17
17
|
In your Gemfile:
|
18
18
|
|
19
19
|
```ruby
|
20
|
-
gem "ransack" # Last officially released gem (Rails 3 and 4)
|
20
|
+
gem "ransack" # Last officially released gem (compatible Rails 3.x and 4.0, but not 4.1)
|
21
21
|
```
|
22
22
|
|
23
|
-
Or if you want to use the
|
23
|
+
Or if you want to use the latest updates (Rails 3.x and 4.0, but not 4.1):
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
gem "ransack", github: "
|
26
|
+
gem "ransack", github: "activerecord-hackery/ransack" # Track git repo
|
27
|
+
```
|
28
|
+
|
29
|
+
If you are on Rails 4.0, you may prefer to use the streamlined, legacy code-free, latest-updates version of Ransack on the [Rails 4 branch](https://github.com/activerecord-hackery/ransack/tree/rails-4):
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
gem "ransack", github: "activerecord-hackery/ransack", branch: "rails-4"
|
33
|
+
```
|
34
|
+
|
35
|
+
Finally, if you are on Rails 4.1 (or 4.2.0.alpha), use the [Rails 4.1 branch](https://github.com/activerecord-hackery/ransack/tree/rails-4.1) which contains the latest updates also on master and rails-4. In your Gemfile you'll need to include (for the moment) both Ransack and Polyamorous as follows:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem "ransack", github: "activerecord-hackery/ransack", branch: "rails-4.1"
|
39
|
+
gem "polyamorous", github: "activerecord-hackery/polyamorous"
|
27
40
|
```
|
28
41
|
|
29
42
|
## Usage
|
@@ -41,9 +54,11 @@ If you're coming from MetaSearch, things to note:
|
|
41
54
|
primarily to shorten query strings, though advanced queries (below) will still
|
42
55
|
run afoul of URL length limits in most browsers and require a switch to HTTP
|
43
56
|
POST requests. This key is
|
44
|
-
[configurable](https://github.com/
|
57
|
+
[configurable](https://github.com/activerecord-hackery/ransack/wiki/Configuration).
|
58
|
+
|
45
59
|
2. `form_for` is now `search_form_for`, and validates that a Ransack::Search object
|
46
60
|
is passed to it.
|
61
|
+
|
47
62
|
3. Common ActiveRecord::Relation methods are no longer delegated by the search object.
|
48
63
|
Instead, you will get your search results (an ActiveRecord::Relation in the case of
|
49
64
|
the ActiveRecord adapter) via a call to `Search#result`. If passed `distinct: true`,
|
@@ -78,7 +93,7 @@ In your view:
|
|
78
93
|
```
|
79
94
|
|
80
95
|
`cont` (contains) and `start` (starts with) are just two of the available search predicates.
|
81
|
-
See [Constants](https://github.com/
|
96
|
+
See [Constants](https://github.com/activerecord-hackery/ransack/blob/master/lib/ransack/constants.rb) for a full list and the [wiki](https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching) for more description.
|
82
97
|
|
83
98
|
### Advanced Mode
|
84
99
|
|
@@ -116,7 +131,16 @@ end
|
|
116
131
|
|
117
132
|
Once you've done so, you can make use of the helpers in Ransack::Helpers::FormBuilder to
|
118
133
|
construct much more complex search forms, such as the one on the
|
119
|
-
[demo page](http://ransack-demo.heroku.com).
|
134
|
+
[demo page](http://ransack-demo.heroku.com) (source code [here](https://github.com/activerecord-hackery/ransack_demo)).
|
135
|
+
|
136
|
+
### Ransack #search method
|
137
|
+
|
138
|
+
Ransack will try to to make `#search` available in your models, but in the case that `#search` has already been defined, you can use `#ransack` instead. For example the following would be equivalent:
|
139
|
+
|
140
|
+
```
|
141
|
+
Article.search(params[:q])
|
142
|
+
Article.ransack(params[:q])
|
143
|
+
```
|
120
144
|
|
121
145
|
### has_many and belongs_to associations
|
122
146
|
|
@@ -173,6 +197,17 @@ end
|
|
173
197
|
<% end %>
|
174
198
|
```
|
175
199
|
|
200
|
+
## Using SimpleForm
|
201
|
+
|
202
|
+
If you want to combine form builders of ransack and SimpleForm, just set the RANSACK_FORM_BUILDER environment variable before Rails started, e.g. in ``config/application.rb`` before ``require 'rails/all'`` and of course use ``gem 'simple_form'`` in your ``Gemfile``:
|
203
|
+
```ruby
|
204
|
+
require File.expand_path('../boot', __FILE__)
|
205
|
+
|
206
|
+
ENV['RANSACK_FORM_BUILDER'] = '::SimpleForm::FormBuilder'
|
207
|
+
|
208
|
+
require 'rails/all'
|
209
|
+
```
|
210
|
+
|
176
211
|
## I18n
|
177
212
|
|
178
213
|
Take a look at our locale file on ``lib/ransack/locale/en.yml`` to check all available messages. You may also be interested in one of the many translations that are available on:
|
@@ -190,4 +225,4 @@ To support the project:
|
|
190
225
|
|
191
226
|
## Copyright
|
192
227
|
|
193
|
-
Copyright © 2011 [Ernie Miller](http://twitter.com/erniemiller)
|
228
|
+
Copyright © 2011-2014 [Ernie Miller](http://twitter.com/erniemiller)
|
data/lib/ransack.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
1
3
|
require 'ransack/configuration'
|
2
4
|
|
3
5
|
module Ransack
|
@@ -8,7 +10,7 @@ end
|
|
8
10
|
|
9
11
|
Ransack.configure do |config|
|
10
12
|
Ransack::Constants::AREL_PREDICATES.each do |name|
|
11
|
-
config.add_predicate name, :
|
13
|
+
config.add_predicate name, arel_predicate: name
|
12
14
|
end
|
13
15
|
|
14
16
|
Ransack::Constants::DERIVED_PREDICATES.each do |args|
|
@@ -23,4 +25,4 @@ require 'ransack/adapters/active_record' if defined?(::ActiveRecord::Base)
|
|
23
25
|
require 'ransack/helpers'
|
24
26
|
require 'action_controller'
|
25
27
|
|
26
|
-
ActionController::Base.helper Ransack::Helpers::FormHelper
|
28
|
+
ActionController::Base.helper Ransack::Helpers::FormHelper
|
@@ -2,7 +2,7 @@
|
|
2
2
|
if Arel::Nodes::And < Arel::Nodes::Binary
|
3
3
|
class Ransack::Visitor
|
4
4
|
def visit_Ransack_Nodes_And(object)
|
5
|
-
nodes = object.values.map {|o| accept(o)}.compact
|
5
|
+
nodes = object.values.map { |o| accept(o) }.compact
|
6
6
|
return nil unless nodes.size > 0
|
7
7
|
|
8
8
|
if nodes.size > 1
|
@@ -132,9 +132,15 @@ module Arel
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def visit_Arel_Nodes_NamedFunction o
|
135
|
-
"#{
|
136
|
-
|
137
|
-
|
135
|
+
"#{
|
136
|
+
o.name
|
137
|
+
}(#{
|
138
|
+
o.distinct ? 'DISTINCT ' : ''
|
139
|
+
}#{
|
140
|
+
o.expressions.map { |x| visit x }.join(', ')
|
141
|
+
})#{
|
142
|
+
o.alias ? " AS #{visit o.alias}" : ''
|
143
|
+
}"
|
138
144
|
end
|
139
145
|
|
140
146
|
def visit_Arel_Nodes_And o
|
@@ -146,13 +152,17 @@ module Arel
|
|
146
152
|
end
|
147
153
|
|
148
154
|
def visit_Arel_Nodes_Values o
|
149
|
-
"VALUES (#{
|
155
|
+
"VALUES (#{
|
156
|
+
o.expressions.zip(o.columns)
|
157
|
+
.map { |value, attr|
|
150
158
|
if Nodes::SqlLiteral === value
|
151
159
|
visit_Arel_Nodes_SqlLiteral value
|
152
160
|
else
|
153
161
|
quote(value, attr && column_for(attr))
|
154
162
|
end
|
155
|
-
}
|
163
|
+
}
|
164
|
+
.join ', '
|
165
|
+
})"
|
156
166
|
end
|
157
167
|
end
|
158
168
|
end
|
@@ -26,9 +26,11 @@ module Ransack
|
|
26
26
|
viz = Visitor.new
|
27
27
|
relation = @object.where(viz.accept(search.base))
|
28
28
|
if search.sorts.any?
|
29
|
-
relation = relation.except(:order)
|
29
|
+
relation = relation.except(:order)
|
30
|
+
.reorder(viz.accept(search.sorts))
|
30
31
|
end
|
31
|
-
opts[:distinct] ?
|
32
|
+
opts[:distinct] ?
|
33
|
+
relation.select("DISTINCT #{@klass.quoted_table_name}.*") : relation
|
32
34
|
end
|
33
35
|
|
34
36
|
def attribute_method?(str, klass = @klass)
|
@@ -39,10 +41,15 @@ module Ransack
|
|
39
41
|
elsif (segments = str.split(/_/)).size > 1
|
40
42
|
remainder = []
|
41
43
|
found_assoc = nil
|
42
|
-
while !found_assoc && remainder.unshift(segments.pop) &&
|
43
|
-
|
44
|
+
while !found_assoc && remainder.unshift(segments.pop) &&
|
45
|
+
segments.size > 0 do
|
46
|
+
assoc, poly_class = unpolymorphize_association(
|
47
|
+
segments.join('_')
|
48
|
+
)
|
44
49
|
if found_assoc = get_association(assoc, klass)
|
45
|
-
exists = attribute_method?(
|
50
|
+
exists = attribute_method?(
|
51
|
+
remainder.join('_'), poly_class || found_assoc.klass
|
52
|
+
)
|
46
53
|
end
|
47
54
|
end
|
48
55
|
end
|
@@ -56,7 +63,9 @@ module Ransack
|
|
56
63
|
|
57
64
|
def type_for(attr)
|
58
65
|
return nil unless attr && attr.valid?
|
59
|
-
klassify(attr.parent)
|
66
|
+
klassify(attr.parent)
|
67
|
+
.columns_hash[attr.arel_attribute.name.to_s]
|
68
|
+
.type
|
60
69
|
end
|
61
70
|
|
62
71
|
private
|
@@ -69,22 +78,26 @@ module Ransack
|
|
69
78
|
elsif (segments = str.split(/_/)).size > 1
|
70
79
|
remainder = []
|
71
80
|
found_assoc = nil
|
72
|
-
while remainder.unshift(segments.pop) && segments.size > 0 &&
|
81
|
+
while remainder.unshift(segments.pop) && segments.size > 0 &&
|
82
|
+
!found_assoc do
|
73
83
|
assoc, klass = unpolymorphize_association(segments.join('_'))
|
74
84
|
if found_assoc = get_association(assoc, parent)
|
75
|
-
join = build_or_find_association(
|
76
|
-
|
85
|
+
join = build_or_find_association(
|
86
|
+
found_assoc.name, parent, klass
|
87
|
+
)
|
88
|
+
parent, attr_name = get_parent_and_attribute_name(
|
89
|
+
remainder.join('_'), join
|
90
|
+
)
|
77
91
|
end
|
78
92
|
end
|
79
93
|
end
|
80
|
-
|
81
94
|
[parent, attr_name]
|
82
95
|
end
|
83
96
|
|
84
97
|
def get_association(str, parent = @base)
|
85
98
|
klass = klassify parent
|
86
99
|
ransackable_association?(str, klass) &&
|
87
|
-
klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
|
100
|
+
klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
|
88
101
|
end
|
89
102
|
|
90
103
|
def join_dependency(relation)
|
@@ -114,9 +127,9 @@ module Ransack
|
|
114
127
|
association_joins = buckets['association_join'] || []
|
115
128
|
stashed_association_joins = buckets['stashed_join'] || []
|
116
129
|
join_nodes = buckets['join_node'] || []
|
117
|
-
string_joins = (buckets['string_join'] || [])
|
118
|
-
|
119
|
-
|
130
|
+
string_joins = (buckets['string_join'] || [])
|
131
|
+
.map { |x| x.strip }
|
132
|
+
.uniq
|
120
133
|
|
121
134
|
join_list = relation.send :custom_join_sql, (string_joins + join_nodes)
|
122
135
|
|
@@ -134,13 +147,16 @@ module Ransack
|
|
134
147
|
end
|
135
148
|
|
136
149
|
def build_or_find_association(name, parent = @base, klass = nil)
|
137
|
-
found_association = @join_dependency.join_associations
|
150
|
+
found_association = @join_dependency.join_associations
|
151
|
+
.detect do |assoc|
|
138
152
|
assoc.reflection.name == name &&
|
139
153
|
assoc.parent == parent &&
|
140
154
|
(!klass || assoc.reflection.klass == klass)
|
141
155
|
end
|
142
156
|
unless found_association
|
143
|
-
@join_dependency.send(
|
157
|
+
@join_dependency.send(
|
158
|
+
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
159
|
+
)
|
144
160
|
found_association = @join_dependency.join_associations.last
|
145
161
|
# Leverage the stashed association functionality in AR
|
146
162
|
@object = @object.joins(found_association)
|
@@ -25,9 +25,12 @@ module Ransack
|
|
25
25
|
viz = Visitor.new
|
26
26
|
relation = @object.where(viz.accept(search.base))
|
27
27
|
if search.sorts.any?
|
28
|
-
relation = relation.except(:order)
|
28
|
+
relation = relation.except(:order)
|
29
|
+
.reorder(viz.accept(search.sorts))
|
29
30
|
end
|
30
|
-
opts[:distinct] ?
|
31
|
+
opts[:distinct] ?
|
32
|
+
relation.select("DISTINCT #{@klass.quoted_table_name}.*") :
|
33
|
+
relation
|
31
34
|
end
|
32
35
|
|
33
36
|
def attribute_method?(str, klass = @klass)
|
@@ -38,10 +41,15 @@ module Ransack
|
|
38
41
|
elsif (segments = str.split(/_/)).size > 1
|
39
42
|
remainder = []
|
40
43
|
found_assoc = nil
|
41
|
-
while !found_assoc && remainder.unshift(segments.pop) &&
|
42
|
-
|
44
|
+
while !found_assoc && remainder.unshift(segments.pop) &&
|
45
|
+
segments.size > 0 do
|
46
|
+
assoc, poly_class = unpolymorphize_association(
|
47
|
+
segments.join('_')
|
48
|
+
)
|
43
49
|
if found_assoc = get_association(assoc, klass)
|
44
|
-
exists = attribute_method?(
|
50
|
+
exists = attribute_method?(
|
51
|
+
remainder.join('_'), poly_class || found_assoc.klass
|
52
|
+
)
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
@@ -75,11 +83,16 @@ module Ransack
|
|
75
83
|
elsif (segments = str.split(/_/)).size > 1
|
76
84
|
remainder = []
|
77
85
|
found_assoc = nil
|
78
|
-
while remainder.unshift(segments.pop) && segments.size > 0 &&
|
86
|
+
while remainder.unshift(segments.pop) && segments.size > 0 &&
|
87
|
+
!found_assoc do
|
79
88
|
assoc, klass = unpolymorphize_association(segments.join('_'))
|
80
89
|
if found_assoc = get_association(assoc, parent)
|
81
|
-
join = build_or_find_association(
|
82
|
-
|
90
|
+
join = build_or_find_association(
|
91
|
+
found_assoc.name, parent, klass
|
92
|
+
)
|
93
|
+
parent, attr_name = get_parent_and_attribute_name(
|
94
|
+
remainder.join('_'), join
|
95
|
+
)
|
83
96
|
end
|
84
97
|
end
|
85
98
|
end
|
@@ -90,7 +103,7 @@ module Ransack
|
|
90
103
|
def get_association(str, parent = @base)
|
91
104
|
klass = klassify parent
|
92
105
|
ransackable_association?(str, klass) &&
|
93
|
-
klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
|
106
|
+
klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
|
94
107
|
end
|
95
108
|
|
96
109
|
def join_dependency(relation)
|
@@ -120,11 +133,12 @@ module Ransack
|
|
120
133
|
association_joins = buckets['association_join'] || []
|
121
134
|
stashed_association_joins = buckets['stashed_join'] || []
|
122
135
|
join_nodes = buckets['join_node'] || []
|
123
|
-
string_joins = (buckets['string_join'] || [])
|
124
|
-
|
125
|
-
|
136
|
+
string_joins = (buckets['string_join'] || [])
|
137
|
+
.map { |x| x.strip }
|
138
|
+
.uniq
|
126
139
|
|
127
|
-
join_list = relation.send :custom_join_ast,
|
140
|
+
join_list = relation.send :custom_join_ast,
|
141
|
+
relation.table.from(relation.table), string_joins
|
128
142
|
|
129
143
|
join_dependency = JoinDependency.new(
|
130
144
|
relation.klass,
|
@@ -140,13 +154,16 @@ module Ransack
|
|
140
154
|
end
|
141
155
|
|
142
156
|
def build_or_find_association(name, parent = @base, klass = nil)
|
143
|
-
found_association = @join_dependency.join_associations
|
157
|
+
found_association = @join_dependency.join_associations
|
158
|
+
.detect do |assoc|
|
144
159
|
assoc.reflection.name == name &&
|
145
160
|
assoc.parent == parent &&
|
146
161
|
(!klass || assoc.reflection.klass == klass)
|
147
162
|
end
|
148
163
|
unless found_association
|
149
|
-
@join_dependency.send(
|
164
|
+
@join_dependency.send(
|
165
|
+
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
166
|
+
)
|
150
167
|
found_association = @join_dependency.join_associations.last
|
151
168
|
# Leverage the stashed association functionality in AR
|
152
169
|
@object = @object.joins(found_association)
|