From 7ee824a83a5eb74682c5c01fdf404ced53f033d5 Mon Sep 17 00:00:00 2001 From: Aaron Lipman Date: Sun, 7 Jun 2020 22:15:18 -0400 Subject: [PATCH] Add ransack! method which raises error if passed unknown condition --- CHANGELOG.md | 4 ++ Gemfile | 2 +- README.md | 37 +++++++++++++++++++ lib/ransack/adapters/active_record/base.rb | 4 ++ lib/ransack/search.rb | 3 +- .../adapters/active_record/base_spec.rb | 4 ++ spec/ransack/search_spec.rb | 30 ++++++++++++++- 7 files changed, 80 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a487e427..44d8caba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +* Add `ActiveRecord::Base.ransack!` which raises error if passed unknown condition + + *Aaron Lipman* + ## 2.4.0 - 2020-11-27 * diff --git a/Gemfile b/Gemfile index ea198d7d2..6824ba819 100644 --- a/Gemfile +++ b/Gemfile @@ -42,7 +42,7 @@ else gem 'actionpack' end end -gem 'mysql2', '~> 0.5.2' +# gem 'mysql2', '~> 0.5.2' group :test do gem 'machinist', '~> 1.0.6' diff --git a/README.md b/README.md index ec4c1a992..7055173d4 100644 --- a/README.md +++ b/README.md @@ -670,6 +670,43 @@ Trying it out in `rails console`: That's it! Now you know how to whitelist/blacklist various elements in Ransack. +### Handling unknown predicates or attributes + +By default, Ransack will ignore any unknown predicates or attributes: + +```ruby +Article.ransack(unknown_attr_eq: 'Ernie').result.to_sql +=> SELECT "articles".* FROM "articles" +``` + +Ransack may be configured to raise an error if passed an unknown predicate or +attributes, by setting the `ignore_unknown_conditions` option to `false` in your +Ransack initializer file at `config/initializers/ransack.rb`: + +```ruby +Ransack.configure do |c| + # Raise errors if a query contains an unknown predicate or attribute. + # Default is true (do not raise error on unknown conditions). + c.ignore_unknown_conditions = false +end +``` + +```ruby +Article.ransack(unknown_attr_eq: 'Ernie') +# ArgumentError (Invalid search term unknown_attr_eq) +``` + +As an alternative to setting a global configuration option, the `.ransack!` +class method also raises an error if passed an unknown condition: + +```ruby +Article.ransack!(unknown_attr_eq: 'Ernie') +# ArgumentError: Invalid search term unknown_attr_eq +``` + +This is equivilent to the `ignore_unknown_conditions` configuration option, +except it may be applied on a case-by-case basis. + ### Using Scopes/Class Methods Continuing on from the preceding section, searching by scopes requires defining diff --git a/lib/ransack/adapters/active_record/base.rb b/lib/ransack/adapters/active_record/base.rb index fa8ed32ee..9ad348a75 100644 --- a/lib/ransack/adapters/active_record/base.rb +++ b/lib/ransack/adapters/active_record/base.rb @@ -18,6 +18,10 @@ def ransack(params = {}, options = {}) Search.new(self, params, options) end + def ransack!(params = {}, options = {}) + ransack(params, options.merge(ignore_unknown_conditions: false)) + end + def ransacker(name, opts = {}, &block) self._ransackers = _ransackers.merge name.to_s => Ransacker .new(self, name, opts, &block) diff --git a/lib/ransack/search.rb b/lib/ransack/search.rb index 9b4384443..35ca06539 100644 --- a/lib/ransack/search.rb +++ b/lib/ransack/search.rb @@ -30,6 +30,7 @@ def initialize(object, params = {}, options = {}) ) @scope_args = {} @sorts ||= [] + @ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true build(params.with_indifferent_access) end @@ -45,7 +46,7 @@ def build(params) base.send("#{key}=", value) elsif @context.ransackable_scope?(key, @context.object) add_scope(key, value) - elsif !Ransack.options[:ignore_unknown_conditions] + elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions raise ArgumentError, "Invalid search term #{key}" end end diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 180d5e6a1..3ede567d1 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -122,6 +122,10 @@ module ActiveRecord expect { Person.ransack('') }.to_not raise_error end + it 'raises exception if ransack! called with unknown condition' do + expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error + end + it 'does not modify the parameters' do params = { name_eq: '' } expect { Person.ransack(params) }.not_to change { params } diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index a824f1373..0b134b2c5 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -232,7 +232,7 @@ module Ransack context 'with an invalid condition' do subject { Search.new(Person, unknown_attr_eq: 'Ernie') } - context 'when ignore_unknown_conditions is false' do + context 'when ignore_unknown_conditions configuration option is false' do before do Ransack.configure { |c| c.ignore_unknown_conditions = false } end @@ -240,13 +240,39 @@ module Ransack specify { expect { subject }.to raise_error ArgumentError } end - context 'when ignore_unknown_conditions is true' do + context 'when ignore_unknown_conditions configuration option is true' do before do Ransack.configure { |c| c.ignore_unknown_conditions = true } end specify { expect { subject }.not_to raise_error } end + + subject(:with_ignore_unknown_conditions_false) { + Search.new(Person, + { unknown_attr_eq: 'Ernie' }, + { ignore_unknown_conditions: false } + ) + } + + subject(:with_ignore_unknown_conditions_true) { + Search.new(Person, + { unknown_attr_eq: 'Ernie' }, + { ignore_unknown_conditions: true } + ) + } + + context 'when ignore_unknown_conditions search parameter is absent' do + specify { expect { subject }.not_to raise_error } + end + + context 'when ignore_unknown_conditions search parameter is false' do + specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError } + end + + context 'when ignore_unknown_conditions search parameter is true' do + specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error } + end end it 'does not modify the parameters' do