Skip to content

Commit

Permalink
Invalid combinators to raise and visitors to tolerate combinator case…
Browse files Browse the repository at this point in the history
… and symbol differences
  • Loading branch information
bagp1 committed Dec 4, 2023
1 parent cc624b9 commit 650944d
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Dangerous searches (e.g. ransack!) will now raise an ArgumentError when passed an unrecognised combinator rather than silently fall back on "AND".
* Combinator values "OR" and :or are now treated as the expected 'or'.

## 4.1.0 - 2023-10-23

### 🚀 Features
Expand Down
3 changes: 2 additions & 1 deletion lib/ransack/nodes/condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ def combinator
end

def combinator=(val)
@combinator = Constants::AND_OR.detect { |v| v == val.to_s } || nil
super
end

alias :m= :combinator=
alias :m :combinator

Expand Down
6 changes: 5 additions & 1 deletion lib/ransack/nodes/grouping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ class Grouping < Node

delegate :each, to: :values

def combinator=(val)
super
end

def initialize(context, combinator = nil)
super(context)
self.combinator = combinator.to_s if combinator
self.combinator = combinator if combinator
end

def persisted?
Expand Down
4 changes: 4 additions & 0 deletions lib/ransack/nodes/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def translate(key, options = {})
end
end

def combinator=(val)
@combinator = Constants::AND_OR.detect { |v| v == val&.downcase&.to_s } || nil
end

end
end
end
7 changes: 7 additions & 0 deletions lib/ransack/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ def build(params)
elsif @context.ransackable_scope?(key, @context.object)
add_scope(key, value)
elsif base.attribute_method?(key)
if (key == Constants::COMBINATOR &&
Constants::AND_OR.exclude?(value.to_s) &&
(!Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions))

raise ArgumentError, "Invalid combinator #{value}"
end

base.send("#{key}=", value)
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
raise ArgumentError, "Invalid search term #{key}"
Expand Down
46 changes: 46 additions & 0 deletions spec/ransack/search_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,52 @@ module Ransack
end
end

context 'with an invalid combinator' do
subject { Search.new(Person, name_eq: 'foobar', combinator: 'unknown') }

context 'when ignore_unknown_conditions configuration option is false' do
before do
Ransack.configure { |c| c.ignore_unknown_conditions = false }
end

specify { expect { subject }.to raise_error ArgumentError }
end

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,
{ name_eq: 'foobar', combinator: 'unknown' },
{ ignore_unknown_conditions: false }
)
}

subject(:with_ignore_unknown_conditions_true) {
Search.new(Person,
{ name_eq: 'foobar', combinator: 'unknown' },
{ 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
params = { name_eq: '' }
expect { Search.new(Person, params) }.not_to change { params }
Expand Down
37 changes: 37 additions & 0 deletions spec/ransack/visitor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'spec_helper'

module Ransack
describe Visitor do

let(:viz) { Visitor.new }

shared_examples 'an or combinator' do | combinator |
it 'routes to #visit_or' do
expect(viz).to receive(:visit_or)
expect(viz).to_not receive(:visit_and)

grouping = Ransack::Nodes::Grouping.new(nil, combinator)
viz.visit_Ransack_Nodes_Grouping(grouping)
end
end

shared_examples 'not an or combinator' do | combinator |
it 'routes to #visit_or' do
expect(viz).to_not receive(:visit_or)
expect(viz).to receive(:visit_and)

grouping = Ransack::Nodes::Grouping.new(nil, combinator)
viz.visit_Ransack_Nodes_Grouping(grouping)
end
end

context 'combinator "or"' do include_examples 'an or combinator', 'or' end
context 'combinator "OR"' do include_examples 'an or combinator', 'OR' end
context 'combinator ":or"' do include_examples 'an or combinator', :or end

context 'combinator "and"' do include_examples 'not an or combinator', 'and' end
context 'combinator "AND"' do include_examples 'not an or combinator', 'AND' end
context 'combinator ":and"' do include_examples 'not an or combinator', :and end
context 'combinator "unknown"' do include_examples 'not an or combinator', 'unknown' end
end
end

0 comments on commit 650944d

Please sign in to comment.