active_admin_filter_extensions 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d830dd4ae0f8db4ee8e74080ea33d93071aaafc4a7ad30b0b7b5ab67da1ceeca
4
- data.tar.gz: da0e3e34de9845286118c35f11078230e6add9693f62bd37b63745d1ac6c7cb3
3
+ metadata.gz: d0c78b8910b00dd6300b7b3eebb5e5538eb534df7bb4ae2f37e206ed7c7e0a9b
4
+ data.tar.gz: 39b6b4f970c13cf26b71837b73463e9b1d13468eb2c6150deb4513759ddad7a6
5
5
  SHA512:
6
- metadata.gz: 42761e0adb059a3e53670ce31ed273de6eabfccef2f4339236022e74008229bcc2e8964a4545cd0f54ab20d0b48c6619904938a7d47e7bac114e34c6e2642819
7
- data.tar.gz: '02581ca6ab8af05d3a5c1aa8e483aef78ae21085432d957609d179efc9c7afe48b8c5f05230c9003acbbfb057a7eab505896174a42fd2442b0af8c45ff28f286'
6
+ metadata.gz: a7854f6af602da404309b0734e83ab47b1d60df0a7ed7667abecc4525efb5e0b1d70f9f459bf43a30179e3823bf5621efab8ae969494cec12ffe9830d8214904
7
+ data.tar.gz: a5681dbf451ed707c92c6ce2be45cba12e4f7aaa81854eed31b783fc4335aa65720c26f7e6f83ef67a7d9638a93034bd8a2e20172efb37c9492986bb7464d167
data/README.md CHANGED
@@ -358,7 +358,10 @@ Four prints in small type:
358
358
  never a condition and is never touched.
359
359
  * **Anything that reads `params[:q]` for the effective filters** (drill-down links, exports)
360
360
  should read `filtering_params` instead - on the rendered page they agree, but only
361
- `filtering_params` is also right on the non-redirected formats.
361
+ `filtering_params` is also right on the non-redirected formats. A page that translates those
362
+ values before passing them on - renaming a key an input suffixed, turning a sentinel into
363
+ another predicate - wants `applied_filter_params`: the same values as an indifferent copy,
364
+ safe to read by symbol and to mutate. Both are helpers, so a view can call them too.
362
365
 
363
366
  Tested against Active Admin 3.5 on Rails 8.0 and 8.1, under Ruby 3.3, 3.4 and 4.0.
364
367
 
@@ -28,7 +28,7 @@ module ActiveAdminFilterExtensions
28
28
  # #filter_defaults_apply? which lets defaults through on a partly filtered request keeps
29
29
  # the values that were actually asked for.
30
30
  #
31
- # @return [Hash, ActionController::Parameters] values passed to Ransack
31
+ # @return [Hash] values passed to Ransack
32
32
  def filtering_params
33
33
  requested = requested_filtering_params
34
34
  # Materialized on every path: computing it is also what validates, loudly, that every
@@ -56,6 +56,20 @@ module ActiveAdminFilterExtensions
56
56
  defaults.merge(requested || {})
57
57
  end
58
58
 
59
+ # The same values, as an indifferent deep copy: readable by symbol and safe to mutate. A page
60
+ # that builds its own collection or its own links usually has to translate those values
61
+ # into whatever it talks to - renaming a key an input suffixed, turning a sentinel into a
62
+ # different predicate - and must not do that to the Hash #filtering_params itself returns,
63
+ # which is also what fills the filters form and decides the canonicalizing redirect.
64
+ #
65
+ # @return [ActiveSupport::HashWithIndifferentAccess]
66
+ def applied_filter_params
67
+ # deep_dup, not just with_indifferent_access: that copies the containers but keeps the
68
+ # value objects, so a `gsub!` or `replace` on a String value would reach back into the
69
+ # request's own and change what the next #filtering_params answers.
70
+ filtering_params.deep_dup.with_indifferent_access
71
+ end
72
+
59
73
  def complete_with_groups(defaults)
60
74
  with_groups.each do |keys|
61
75
  next unless keys.any? { |key| defaults.key?(key) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveAdminFilterExtensions
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "activeadmin"
4
+ require "active_support/core_ext/object/deep_dup"
4
5
  require "active_admin_filter_extensions/version"
5
6
 
6
7
  # The violation messages live in plain i18n - config/locales/en.yml here, overridable by the
@@ -45,7 +46,8 @@ ActiveAdmin.before_load do |_app|
45
46
  ActiveAdmin::ResourceController.include ActiveAdminFilterExtensions::SearchKeys
46
47
  ActiveAdmin::ResourceController.include ActiveAdminFilterExtensions::RequiredFilters
47
48
  ActiveAdmin::ResourceController.include ActiveAdminFilterExtensions::FilterDefaults
48
- ActiveAdmin::ResourceController.helper_method :filtering_params, :filter_default_values, :visible_filters
49
+ ActiveAdmin::ResourceController.helper_method :filtering_params, :applied_filter_params,
50
+ :filter_default_values, :visible_filters
49
51
 
50
52
  ActiveAdmin::Resource.prepend ActiveAdminFilterExtensions::ResourceExtension
51
53
  ActiveAdmin::ResourceDSL.include ActiveAdminFilterExtensions::Policies::ResourcePolicyDSL
@@ -53,6 +53,36 @@ RSpec.describe ActiveAdminFilterExtensions::DataAccess do
53
53
  end
54
54
  end
55
55
 
56
+ describe "#applied_filter_params" do
57
+ let(:filters) { { position_eq: { extensions: { default: "20" } } } }
58
+
59
+ it "reads by symbol what the request spelled as a String" do
60
+ expect(controller.send(:applied_filter_params)[:position_eq]).to eq("20")
61
+ end
62
+
63
+ it "hands out a copy, so a caller translating the values cannot rewrite the search" do
64
+ applied = controller.send(:applied_filter_params)
65
+ applied[:position_gt] = applied.delete(:position_eq)
66
+
67
+ expect(controller.send(:filtering_params)).to eq("position_eq" => "20")
68
+ expect(searched_with).to eq("position_eq" => "20")
69
+ end
70
+
71
+ context "when the request carries a value of its own" do
72
+ let(:filters) { { title_cont: {} } }
73
+ # Mutable on purpose: with_indifferent_access alone copies the Hash but hands out this
74
+ # very String, so editing it in place would reach back into the request.
75
+ let(:params) { { q: { "title_cont" => String.new("hello") } } }
76
+
77
+ it "copies the values too, so editing one in place cannot reach the request" do
78
+ controller.send(:applied_filter_params)[:title_cont].replace("bye")
79
+
80
+ expect(controller.send(:filtering_params)).to eq("title_cont" => "hello")
81
+ expect(searched_with).to eq("title_cont" => "hello")
82
+ end
83
+ end
84
+ end
85
+
56
86
  describe "a Hash default" do
57
87
  let(:filters) { { created_at: { as: :date_range, extensions: { default: { gteq: "2020-01-01" } } } } }
58
88
 
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/object/blank"
4
+ require "active_support/core_ext/object/deep_dup"
4
5
  require "active_support/core_ext/hash/indifferent_access"
5
6
  require "active_support/hash_with_indifferent_access"
6
7
  # Pure Ruby, no Active Admin boot required - `visible_filters` resolves `:if` / `:unless` with it.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_admin_filter_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Fedoronchuk