Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions lib/active_admin_filter_extensions/policies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,29 @@ def with_groups

# The filter's own predicate dropdown submits _gt/_lt/_not_eq and friends beside the
# derived head key; a value policy guarding only the head leaves the same column one
# dropdown click from unpoliced. Siblings = request keys naming the same attribute.
# dropdown click from unpoliced. Siblings = request keys naming the same attribute,
# minus the predicates answered by a boolean rather than by a value of the attribute's
# own type: `?q[customer_id_null]=true` carries "true", which `sanitize: :digits`
# empties and `validate: :integer` refuses - the reset would then drop a condition a
# drill-down link spelled out. A boolean predicate the filter declares itself stays
# policed: that one its author asked for.
def sibling_predicate_keys(q, keys)
bases = keys.map { |key| strip_ransack_predicate(key) }
q.keys.select { |key| bases.include?(strip_ransack_predicate(key)) }
declared = keys.map(&:to_s)
q.keys.select do |key|
next false unless bases.include?(strip_ransack_predicate(key))

declared.include?(key.to_s) || !boolean_predicate?(key)
end
end

def boolean_predicate?(name)
# Without Ransack there is nothing to ask - and nothing is stripped either, so a
# sibling can only be the declared key itself.
return false unless defined?(::Ransack::Predicate)

predicate = ::Ransack::Predicate.detect_from_string(name.to_s)
predicate && ::Ransack::Predicate.named(predicate)&.type == :boolean
end

def strip_ransack_predicate(name)
Expand Down
2 changes: 1 addition & 1 deletion lib/active_admin_filter_extensions/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module ActiveAdminFilterExtensions
VERSION = "1.0.0"
VERSION = "1.0.1"
end
13 changes: 13 additions & 0 deletions spec/integration/numeric_builtins_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ def query_of(url)
expect(page).to have_no_content("drop me")
end

it "leaves a boolean predicate of the same attribute to Ransack" do
# `?q[position_null]=true` is answered by "true", not by a value of the column's own
# type: the digits sanitizer would empty it and the integer validator refuse it, and the
# reset would drop a condition the admin's own drill-down link spelled out.
Post.create!(title: "no position", body: "no position body", status: "draft")

visit "/admin/integer_posts?q%5Bposition_null%5D=true"

expect(query_of(page.current_url)["q"]).to eq("position_null" => "true")
expect(page).to have_content("no position")
expect(page).to have_no_content("keep me")
end

it "sanitizes a sibling predicate too" do
visit "/admin/integer_posts?q%5Bposition_lt%5D=2%200a"

Expand Down
Loading