Skip to content

Commit a9e84e1

Browse files
authored
Merge pull request #1132 from alipman88/add_ransack_bang
Add ransack! method which raises error if passed unknown condition
2 parents 150eeb2 + f085e8a commit a9e84e1

File tree

6 files changed

+121
-22
lines changed

6 files changed

+121
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
* Add `ActiveRecord::Base.ransack!` which raises error if passed unknown condition
4+
5+
*Aaron Lipman*
6+
37
## 2.4.0 - 2020-11-27
48

59
*

README.md

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,14 @@ gem 'ransack', github: 'activerecord-hackery/ransack'
4141

4242
## Usage
4343

44-
Ransack can be used in one of two modes, simple or advanced.
44+
Ransack can be used in one of two modes, simple or advanced. For
45+
searching/filtering not requiring complex boolean logic, Ransack's simple
46+
mode should meet your needs.
4547

46-
### Simple Mode
47-
48-
This mode works much like MetaSearch, for those of you who are familiar with
49-
it, and requires very little setup effort.
50-
51-
If you're coming from MetaSearch, things to note:
48+
If you're coming from MetaSearch (Ransack's predecessor), refer to the
49+
[Updating From MetaSearch](#updating-from-metasearch) section
5250

53-
1. The default param key for search params is now `:q`, instead of `:search`.
54-
This is primarily to shorten query strings, though advanced queries (below)
55-
will still run afoul of URL length limits in most browsers and require a
56-
switch to HTTP POST requests. This key is [configurable](https://github.com/activerecord-hackery/ransack/wiki/Configuration).
57-
58-
2. `form_for` is now `search_form_for`, and validates that a Ransack::Search
59-
object is passed to it.
60-
61-
3. Common ActiveRecord::Relation methods are no longer delegated by the
62-
search object. Instead, you will get your search results (an
63-
ActiveRecord::Relation in the case of the ActiveRecord adapter) via a call to
64-
`Ransack#result`.
51+
### Simple Mode
6552

6653
#### In your controller
6754

@@ -84,6 +71,20 @@ def index
8471
end
8572
```
8673

74+
##### Default search parameter
75+
76+
Ransack uses a default `:q` param key for search params. This may be changed by
77+
setting the `search_key` option in a Ransack initializer file (typically
78+
`config/initializers/ransack.rb`):
79+
80+
```
81+
Ransack.configure do |c|
82+
# Change default search parameter key name.
83+
# Default key name is :q
84+
c.search_key = :query
85+
end
86+
```
87+
8788
#### In your view
8889

8990
The two primary Ransack view helpers are `search_form_for` and `sort_link`,
@@ -670,6 +671,43 @@ Trying it out in `rails console`:
670671

671672
That's it! Now you know how to whitelist/blacklist various elements in Ransack.
672673

674+
### Handling unknown predicates or attributes
675+
676+
By default, Ransack will ignore any unknown predicates or attributes:
677+
678+
```ruby
679+
Article.ransack(unknown_attr_eq: 'Ernie').result.to_sql
680+
=> SELECT "articles".* FROM "articles"
681+
```
682+
683+
Ransack may be configured to raise an error if passed an unknown predicate or
684+
attributes, by setting the `ignore_unknown_conditions` option to `false` in your
685+
Ransack initializer file at `config/initializers/ransack.rb`:
686+
687+
```ruby
688+
Ransack.configure do |c|
689+
# Raise errors if a query contains an unknown predicate or attribute.
690+
# Default is true (do not raise error on unknown conditions).
691+
c.ignore_unknown_conditions = false
692+
end
693+
```
694+
695+
```ruby
696+
Article.ransack(unknown_attr_eq: 'Ernie')
697+
# ArgumentError (Invalid search term unknown_attr_eq)
698+
```
699+
700+
As an alternative to setting a global configuration option, the `.ransack!`
701+
class method also raises an error if passed an unknown condition:
702+
703+
```ruby
704+
Article.ransack!(unknown_attr_eq: 'Ernie')
705+
# ArgumentError: Invalid search term unknown_attr_eq
706+
```
707+
708+
This is equivilent to the `ignore_unknown_conditions` configuration option,
709+
except it may be applied on a case-by-case basis.
710+
673711
### Using Scopes/Class Methods
674712

675713
Continuing on from the preceding section, searching by scopes requires defining
@@ -866,6 +904,28 @@ en:
866904
title: Old Ransack Namespaced Title
867905
```
868906

907+
### Updating From MetaSearch
908+
909+
Ransack works much like MetaSearch, for those of you who are familiar with
910+
it, and requires very little setup effort.
911+
912+
If you're coming from MetaSearch, things to note:
913+
914+
1. The default param key for search params is now `:q`, instead of `:search`.
915+
This is primarily to shorten query strings, though advanced queries (below)
916+
will still run afoul of URL length limits in most browsers and require a
917+
switch to HTTP POST requests. This key is
918+
[configurable](default-search-parameter) via setting the `search_key` option
919+
in your Ransack intitializer file.
920+
921+
2. `form_for` is now `search_form_for`, and validates that a Ransack::Search
922+
object is passed to it.
923+
924+
3. Common ActiveRecord::Relation methods are no longer delegated by the
925+
search object. Instead, you will get your search results (an
926+
ActiveRecord::Relation in the case of the ActiveRecord adapter) via a call to
927+
`Ransack#result`.
928+
869929
## Mongoid
870930

871931
Mongoid support has been moved to its own gem at [ransack-mongoid](https://github.com/activerecord-hackery/ransack-mongoid).

lib/ransack/adapters/active_record/base.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def ransack(params = {}, options = {})
1818
Search.new(self, params, options)
1919
end
2020

21+
def ransack!(params = {}, options = {})
22+
ransack(params, options.merge(ignore_unknown_conditions: false))
23+
end
24+
2125
def ransacker(name, opts = {}, &block)
2226
self._ransackers = _ransackers.merge name.to_s => Ransacker
2327
.new(self, name, opts, &block)

lib/ransack/search.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def initialize(object, params = {}, options = {})
3030
)
3131
@scope_args = {}
3232
@sorts ||= []
33+
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
3334
build(params.with_indifferent_access)
3435
end
3536

@@ -45,7 +46,7 @@ def build(params)
4546
base.send("#{key}=", value)
4647
elsif @context.ransackable_scope?(key, @context.object)
4748
add_scope(key, value)
48-
elsif !Ransack.options[:ignore_unknown_conditions]
49+
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
4950
raise ArgumentError, "Invalid search term #{key}"
5051
end
5152
end

spec/ransack/adapters/active_record/base_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ module ActiveRecord
122122
expect { Person.ransack('') }.to_not raise_error
123123
end
124124

125+
it 'raises exception if ransack! called with unknown condition' do
126+
expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error
127+
end
128+
125129
it 'does not modify the parameters' do
126130
params = { name_eq: '' }
127131
expect { Person.ransack(params) }.not_to change { params }

spec/ransack/search_spec.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,21 +232,47 @@ module Ransack
232232
context 'with an invalid condition' do
233233
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
234234

235-
context 'when ignore_unknown_conditions is false' do
235+
context 'when ignore_unknown_conditions configuration option is false' do
236236
before do
237237
Ransack.configure { |c| c.ignore_unknown_conditions = false }
238238
end
239239

240240
specify { expect { subject }.to raise_error ArgumentError }
241241
end
242242

243-
context 'when ignore_unknown_conditions is true' do
243+
context 'when ignore_unknown_conditions configuration option is true' do
244244
before do
245245
Ransack.configure { |c| c.ignore_unknown_conditions = true }
246246
end
247247

248248
specify { expect { subject }.not_to raise_error }
249249
end
250+
251+
subject(:with_ignore_unknown_conditions_false) {
252+
Search.new(Person,
253+
{ unknown_attr_eq: 'Ernie' },
254+
{ ignore_unknown_conditions: false }
255+
)
256+
}
257+
258+
subject(:with_ignore_unknown_conditions_true) {
259+
Search.new(Person,
260+
{ unknown_attr_eq: 'Ernie' },
261+
{ ignore_unknown_conditions: true }
262+
)
263+
}
264+
265+
context 'when ignore_unknown_conditions search parameter is absent' do
266+
specify { expect { subject }.not_to raise_error }
267+
end
268+
269+
context 'when ignore_unknown_conditions search parameter is false' do
270+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
271+
end
272+
273+
context 'when ignore_unknown_conditions search parameter is true' do
274+
specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error }
275+
end
250276
end
251277

252278
it 'does not modify the parameters' do

0 commit comments

Comments
 (0)