iron_admin 0.5.0 → 0.6.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 +4 -4
- data/app/assets/config/iron_admin_manifest.js +12 -0
- data/app/components/iron_admin/dashboards/metric_card_component.html.haml +8 -3
- data/app/components/iron_admin/dashboards/metric_card_component.rb +21 -1
- data/app/components/iron_admin/form/belongs_to_component.rb +60 -6
- data/app/components/iron_admin/form/nested_form_component.html.haml +28 -0
- data/app/components/iron_admin/form/nested_form_component.rb +81 -0
- data/app/components/iron_admin/resources/data_table_component.html.haml +1 -1
- data/app/components/iron_admin/resources/data_table_component.rb +6 -0
- data/app/components/iron_admin/resources/show_field_component.rb +2 -0
- data/app/controllers/iron_admin/application_controller.rb +32 -1
- data/app/controllers/iron_admin/concerns/action_executable.rb +44 -0
- data/app/controllers/iron_admin/concerns/filterable.rb +84 -0
- data/app/controllers/iron_admin/concerns/json_params_coercion.rb +67 -0
- data/app/controllers/iron_admin/concerns/nested_permittable.rb +36 -0
- data/app/controllers/iron_admin/concerns/scopeable.rb +84 -0
- data/app/controllers/iron_admin/concerns/searchable.rb +13 -16
- data/app/controllers/iron_admin/exports_controller.rb +15 -11
- data/app/controllers/iron_admin/imports_controller.rb +83 -0
- data/app/controllers/iron_admin/live_controller.rb +12 -0
- data/app/controllers/iron_admin/resources_controller.rb +118 -117
- data/app/controllers/iron_admin/search_controller.rb +5 -5
- data/app/controllers/iron_admin/tools_controller.rb +63 -4
- data/app/helpers/iron_admin/application_helper.rb +33 -14
- data/app/helpers/iron_admin/field_display_helper.rb +160 -1
- data/app/javascript/iron_admin/controllers/cp_nested_form_controller.js +113 -0
- data/app/javascript/iron_admin/controllers/filter_operator_controller.js +10 -0
- data/app/javascript/iron_admin/index.js +4 -0
- data/app/views/iron_admin/dashboard/index.html.haml +7 -2
- data/app/views/iron_admin/form/_nested_row.html.haml +70 -0
- data/app/views/iron_admin/imports/new.html.haml +27 -0
- data/app/views/iron_admin/imports/preview.html.haml +31 -0
- data/app/views/iron_admin/resources/_form.html.haml +81 -5
- data/app/views/iron_admin/resources/action_form.html.haml +62 -0
- data/app/views/iron_admin/resources/bulk_action_form.html.haml +62 -0
- data/app/views/iron_admin/resources/index.html.haml +60 -18
- data/app/views/iron_admin/tools/action_form.html.haml +57 -0
- data/app/views/iron_admin/tools/show.html.haml +20 -1
- data/config/importmap.rb +2 -0
- data/config/locales/en.yml +36 -0
- data/config/routes.rb +7 -0
- data/docs/components/filter-components.md +60 -0
- data/docs/getting-started/quick-start.md +17 -1
- data/docs/guides/authentication.md +7 -6
- data/docs/guides/custom-adapters.md +628 -0
- data/docs/guides/extending.md +132 -3
- data/docs/guides/fields.md +1 -1
- data/docs/guides/resources.md +78 -2
- data/docs/guides/troubleshooting.md +29 -0
- data/docs/reference/routes.md +10 -0
- data/lib/generators/iron_admin/install/install_generator.rb +28 -4
- data/lib/generators/iron_admin/install_audit/install_audit_generator.rb +26 -10
- data/lib/iron_admin/action_field.rb +56 -0
- data/lib/iron_admin/adapters/active_record.rb +237 -0
- data/lib/iron_admin/adapters/base.rb +340 -0
- data/lib/iron_admin/adapters/http/column_descriptor.rb +10 -0
- data/lib/iron_admin/adapters/http/configuration.rb +27 -0
- data/lib/iron_admin/adapters/http/connection.rb +117 -0
- data/lib/iron_admin/adapters/http/model_proxy.rb +75 -0
- data/lib/iron_admin/adapters/http/query.rb +111 -0
- data/lib/iron_admin/adapters/http/record.rb +83 -0
- data/lib/iron_admin/adapters/http/type_inferrer.rb +51 -0
- data/lib/iron_admin/adapters/http.rb +241 -0
- data/lib/iron_admin/adapters/mongoid/association_wrapper.rb +74 -0
- data/lib/iron_admin/adapters/mongoid/column_descriptor.rb +10 -0
- data/lib/iron_admin/adapters/mongoid.rb +284 -0
- data/lib/iron_admin/adapters/registry.rb +44 -0
- data/lib/iron_admin/concerns/importable.rb +81 -0
- data/lib/iron_admin/concerns/live_updatable.rb +38 -0
- data/lib/iron_admin/concerns/nestable.rb +69 -0
- data/lib/iron_admin/concerns/soft_deletable.rb +61 -0
- data/lib/iron_admin/configuration.rb +20 -0
- data/lib/iron_admin/dashboard.rb +15 -20
- data/lib/iron_admin/engine.rb +28 -1
- data/lib/iron_admin/errors.rb +29 -0
- data/lib/iron_admin/field_inferrer.rb +61 -22
- data/lib/iron_admin/filters/active_record_query_builder.rb +63 -0
- data/lib/iron_admin/filters/base_query_builder.rb +55 -0
- data/lib/iron_admin/filters/http_query_builder.rb +39 -0
- data/lib/iron_admin/filters/mongoid_query_builder.rb +58 -0
- data/lib/iron_admin/filters/query_builder.rb +12 -0
- data/lib/iron_admin/import/column_mapper.rb +42 -0
- data/lib/iron_admin/import/import_preview.rb +10 -0
- data/lib/iron_admin/import/import_result.rb +10 -0
- data/lib/iron_admin/import/importer.rb +231 -0
- data/lib/iron_admin/import/parser/csv.rb +34 -0
- data/lib/iron_admin/import/parser/json.rb +36 -0
- data/lib/iron_admin/import/type_caster.rb +47 -0
- data/lib/iron_admin/live/broadcaster.rb +43 -0
- data/lib/iron_admin/live/poll_cache.rb +28 -0
- data/lib/iron_admin/live.rb +29 -0
- data/lib/iron_admin/nested_association.rb +15 -0
- data/lib/iron_admin/nested_attributes_validator.rb +25 -0
- data/lib/iron_admin/policy.rb +72 -13
- data/lib/iron_admin/resource.rb +148 -90
- data/lib/iron_admin/resource_registry.rb +77 -4
- data/lib/iron_admin/tool.rb +50 -0
- data/lib/iron_admin/tool_action.rb +73 -0
- data/lib/iron_admin/tool_context.rb +49 -0
- data/lib/iron_admin/version.rb +1 -1
- data/lib/iron_admin.rb +28 -0
- data/vendor/bundle/ruby/3.2.0/cache/addressable-2.9.0.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/crack-1.0.1.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/faraday-2.14.1.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/faraday-net_http-3.4.2.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/hashdiff-1.2.1.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/net-http-0.9.1.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/public_suffix-7.0.5.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/rexml-3.4.4.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/cache/webmock-3.26.2.gem +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/bigdecimal.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/mkmf.log +25 -25
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/date_core.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/mkmf.log +4 -4
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/erb/escape.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/mkmf.log +2 -2
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/io/console.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/mkmf.log +22 -22
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/json/ext/generator.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/json/ext/parser.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/mkmf.log +9 -9
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/mkmf.log +12 -12
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/nio4r_ext.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/mkmf.log +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/prism/prism.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/mkmf.log +7 -7
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/psych.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/racc-1.8.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/racc-1.8.1/racc/cparse.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/redcarpet-3.6.1/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/redcarpet-3.6.1/redcarpet.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/mkmf.log +2 -2
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/stringio.so +0 -0
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/websocket-driver-0.8.0/gem_make.out +6 -6
- data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/websocket-driver-0.8.0/websocket_mask.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/CHANGELOG.md +326 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/LICENSE.txt +202 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/README.md +121 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna/native.rb +66 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna/pure.rb +4710 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna.rb +26 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/template.rb +1040 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/uri.rb +2602 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/version.rb +31 -0
- data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable.rb +4 -0
- data/vendor/bundle/ruby/3.2.0/gems/bigdecimal-4.0.1/ext/bigdecimal/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/bigdecimal-4.0.1/lib/bigdecimal.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/History +58 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/LICENSE +20 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/README.md +43 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/json.rb +113 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/util.rb +17 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/version.rb +3 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/xml.rb +240 -0
- data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack.rb +8 -0
- data/vendor/bundle/ruby/3.2.0/gems/date-3.5.1/ext/date/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/date-3.5.1/lib/date_core.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/erb-6.0.1/ext/erb/escape/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/erb-6.0.1/lib/erb/escape.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/CHANGELOG.md +574 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/LICENSE.md +20 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/README.md +67 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/Rakefile +12 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/examples/client_spec.rb +119 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/examples/client_test.rb +144 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter/test.rb +311 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter.rb +101 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter_registry.rb +30 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/connection.rb +565 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/encoders/flat_params_encoder.rb +105 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/encoders/nested_params_encoder.rb +183 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/error.rb +202 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/logging/formatter.rb +118 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/methods.rb +6 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/middleware.rb +72 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/middleware_registry.rb +83 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/connection_options.rb +23 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/env.rb +204 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/proxy_options.rb +38 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/request_options.rb +23 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/ssl_options.rb +76 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options.rb +219 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/parameters.rb +5 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/rack_builder.rb +248 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/authorization.rb +54 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/instrumentation.rb +58 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/json.rb +70 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/url_encoded.rb +60 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request.rb +139 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/json.rb +74 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/logger.rb +39 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/raise_error.rb +83 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response.rb +95 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils/headers.rb +150 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils/params_hash.rb +61 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils.rb +121 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/version.rb +5 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday.rb +158 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter/test_spec.rb +442 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter_registry_spec.rb +28 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter_spec.rb +55 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/connection_spec.rb +841 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/error_spec.rb +175 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/middleware_registry_spec.rb +31 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/middleware_spec.rb +213 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/env_spec.rb +76 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/options_spec.rb +297 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/proxy_options_spec.rb +79 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/request_options_spec.rb +19 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/params_encoders/flat_spec.rb +42 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/params_encoders/nested_spec.rb +151 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/rack_builder_spec.rb +317 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/authorization_spec.rb +118 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/instrumentation_spec.rb +74 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/json_spec.rb +199 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/url_encoded_spec.rb +93 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request_spec.rb +110 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/json_spec.rb +206 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/logger_spec.rb +299 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/raise_error_spec.rb +286 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response_spec.rb +84 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/utils/headers_spec.rb +109 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/utils_spec.rb +120 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday_spec.rb +43 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/spec_helper.rb +133 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/disabling_stub.rb +14 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/fake_safe_buffer.rb +15 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/faraday_middleware_subclasses.rb +18 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/helper_methods.rb +96 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/adapter.rb +105 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/params_encoder.rb +18 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/request_method.rb +263 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/streaming_response_checker.rb +35 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/LICENSE.md +21 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/README.md +57 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/adapter/net_http.rb +206 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/net_http/version.rb +7 -0
- data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/net_http.rb +10 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/Gemfile +8 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/LICENSE +19 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/README.md +323 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/Rakefile +18 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/changelog.md +127 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/hashdiff.gemspec +39 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/compare_hashes.rb +101 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/diff.rb +185 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/lcs.rb +66 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/lcs_compare_arrays.rb +32 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/linear_compare_array.rb +159 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/patch.rb +88 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/util.rb +155 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/version.rb +5 -0
- data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff.rb +10 -0
- data/vendor/bundle/ruby/3.2.0/gems/io-console-0.8.2/ext/io/console/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/io-console-0.8.2/lib/io/console.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/ext/json/ext/generator/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/ext/json/ext/parser/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/lib/json/ext/generator.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/lib/json/ext/parser.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/BSDL +22 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/COPYING +56 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/README.md +93 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/doc/net-http/examples.rdoc +31 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/doc/net-http/included_getters.rdoc +3 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/exceptions.rb +35 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/generic_request.rb +429 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/header.rb +985 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/proxy_delta.rb +17 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/request.rb +88 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/requests.rb +444 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/response.rb +739 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/responses.rb +1242 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/status.rb +84 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http.rb +2608 -0
- data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/https.rb +23 -0
- data/vendor/bundle/ruby/3.2.0/gems/nio4r-2.7.5/ext/nio4r/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/nio4r-2.7.5/lib/nio4r_ext.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/prism-1.9.0/ext/prism/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/prism-1.9.0/lib/prism/prism.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/psych-5.3.1/ext/psych/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/psych-5.3.1/lib/psych.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/CHANGELOG.md +649 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/Gemfile +16 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/LICENSE.txt +22 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/README.md +231 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/SECURITY.md +24 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/data/list.txt +16298 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/domain.rb +235 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/errors.rb +41 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/list.rb +247 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/rule.rb +350 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/version.rb +14 -0
- data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix.rb +177 -0
- data/vendor/bundle/ruby/3.2.0/gems/racc-1.8.1/ext/racc/cparse/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/racc-1.8.1/lib/racc/cparse.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/redcarpet-3.6.1/ext/redcarpet/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/redcarpet-3.6.1/lib/redcarpet.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/LICENSE.txt +22 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/NEWS.md +843 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/README.md +57 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/context.rdoc +143 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/child.rdoc +87 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/document.rdoc +276 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/element.rdoc +602 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/node.rdoc +97 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/parent.rdoc +267 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/child_toc.rdoc +12 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/document_toc.rdoc +30 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/element_toc.rdoc +55 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/master_toc.rdoc +135 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/node_toc.rdoc +16 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/parent_toc.rdoc +25 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tutorial.rdoc +1358 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/attlistdecl.rb +63 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/attribute.rb +210 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/cdata.rb +68 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/child.rb +96 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/comment.rb +80 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/doctype.rb +306 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/document.rb +471 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/attlistdecl.rb +11 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/dtd.rb +47 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/elementdecl.rb +18 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/entitydecl.rb +57 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/notationdecl.rb +40 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/element.rb +2578 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/encoding.rb +48 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/entity.rb +142 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/default.rb +116 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/pretty.rb +142 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/transitive.rb +58 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/functions.rb +446 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/instruction.rb +79 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/light/node.rb +188 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/namespace.rb +63 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/node.rb +80 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/output.rb +30 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parent.rb +166 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parseexception.rb +53 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/baseparser.rb +949 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/lightparser.rb +59 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/pullparser.rb +213 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/sax2parser.rb +270 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/streamparser.rb +67 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/treeparser.rb +89 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/ultralightparser.rb +57 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/xpathparser.rb +739 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/quickpath.rb +267 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/rexml.rb +39 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/sax2listener.rb +98 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/security.rb +28 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/source.rb +388 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/streamlistener.rb +93 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/text.rb +420 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/undefinednamespaceexception.rb +9 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/relaxng.rb +540 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/validation.rb +144 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/validationexception.rb +10 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xmldecl.rb +130 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xmltokens.rb +85 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xpath.rb +70 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xpath_parser.rb +980 -0
- data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml.rb +3 -0
- data/vendor/bundle/ruby/3.2.0/gems/stringio-3.2.0/ext/stringio/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/stringio-3.2.0/lib/stringio.so +0 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/CHANGELOG.md +2148 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/LICENSE +20 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/README.md +1229 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/api.rb +111 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/assertion_failure.rb +13 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/callback_registry.rb +37 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/config.rb +20 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/cucumber.rb +12 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/deprecation.rb +11 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/errors.rb +19 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +228 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/curb_adapter.rb +354 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +239 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/excon_adapter.rb +167 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter.rb +9 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +21 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/request.rb +28 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/response.rb +95 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/streamer.rb +44 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/webmock.rb +77 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb_adapter.rb +39 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/httpclient_adapter.rb +260 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/manticore_adapter.rb +147 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http.rb +310 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http_response.rb +36 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/patron_adapter.rb +132 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +190 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_including_matcher.rb +19 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/minitest.rb +43 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rack_response.rb +73 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_body_diff.rb +66 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_execution_verifier.rb +79 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_pattern.rb +428 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_registry.rb +37 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_signature.rb +56 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_signature_snippet.rb +63 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_stub.rb +134 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/response.rb +161 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/responses_sequence.rb +42 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers/request_pattern_matcher.rb +80 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers/webmock_matcher.rb +69 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers.rb +29 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec.rb +44 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/stub_registry.rb +84 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/stub_request_snippet.rb +40 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/test_unit.rb +22 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_counter.rb +45 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_keys_stringifier.rb +27 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_validator.rb +19 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/headers.rb +77 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/json.rb +72 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/parse_error.rb +7 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/xml.rb +16 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/query_mapper.rb +283 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/uri.rb +113 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/values_stringifier.rb +22 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/version_checker.rb +113 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/version.rb +5 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/webmock.rb +175 -0
- data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock.rb +61 -0
- data/vendor/bundle/ruby/3.2.0/gems/websocket-driver-0.8.0/ext/websocket-driver/Makefile +3 -3
- data/vendor/bundle/ruby/3.2.0/gems/websocket-driver-0.8.0/lib/websocket_mask.so +0 -0
- data/vendor/bundle/ruby/3.2.0/specifications/addressable-2.9.0.gemspec +29 -0
- data/vendor/bundle/ruby/3.2.0/specifications/crack-1.0.1.gemspec +27 -0
- data/vendor/bundle/ruby/3.2.0/specifications/faraday-2.14.1.gemspec +0 -0
- data/vendor/bundle/ruby/3.2.0/specifications/faraday-net_http-3.4.2.gemspec +26 -0
- data/vendor/bundle/ruby/3.2.0/specifications/hashdiff-1.2.1.gemspec +30 -0
- data/vendor/bundle/ruby/3.2.0/specifications/net-http-0.9.1.gemspec +27 -0
- data/vendor/bundle/ruby/3.2.0/specifications/public_suffix-7.0.5.gemspec +24 -0
- data/vendor/bundle/ruby/3.2.0/specifications/rexml-3.4.4.gemspec +25 -0
- data/vendor/bundle/ruby/3.2.0/specifications/webmock-3.26.2.gemspec +44 -0
- metadata +377 -2
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Quick Start
|
|
2
2
|
|
|
3
|
-
Get a full admin panel running in
|
|
3
|
+
Get a full admin panel running in 6 steps.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
IronAdmin uses [Tailwind CSS](https://tailwindcss.com/) for all styling and requires `tailwindcss-rails` >= 4.0. Ensure your application has a supported version installed:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle add tailwindcss-rails --version ">= 4.0"
|
|
11
|
+
rails tailwindcss:install
|
|
12
|
+
```
|
|
4
13
|
|
|
5
14
|
## 1. Install
|
|
6
15
|
|
|
@@ -81,4 +90,11 @@ class AdminDashboard < IronAdmin::Dashboard
|
|
|
81
90
|
end
|
|
82
91
|
```
|
|
83
92
|
|
|
93
|
+
## 6. Build CSS and Start
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
rails tailwindcss:build
|
|
97
|
+
bin/rails server
|
|
98
|
+
```
|
|
99
|
+
|
|
84
100
|
Visit `/admin` and your admin panel is ready.
|
|
@@ -73,7 +73,7 @@ Per-resource access control:
|
|
|
73
73
|
class UserResource < IronAdmin::Resource
|
|
74
74
|
policy do
|
|
75
75
|
allow :read, :create, :update
|
|
76
|
-
deny :
|
|
76
|
+
deny :destroy, if: ->(user) { !user.superadmin? }
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
```
|
|
@@ -99,19 +99,20 @@ end
|
|
|
99
99
|
### Conditional Policies
|
|
100
100
|
|
|
101
101
|
- `allow` with `if:` receives the **current user**
|
|
102
|
-
- `deny` with `if:` receives the **
|
|
102
|
+
- `deny` with `if:` receives the **current user**
|
|
103
|
+
- Deny rules take precedence over allow rules
|
|
103
104
|
|
|
104
105
|
```ruby
|
|
105
106
|
policy do
|
|
106
107
|
allow :read
|
|
107
108
|
allow :update, if: ->(user) { user.admin? || user.manager? }
|
|
108
|
-
deny :
|
|
109
|
+
deny :destroy, if: ->(user) { !user.superadmin? }
|
|
109
110
|
end
|
|
110
111
|
```
|
|
111
112
|
|
|
112
113
|
### Custom Action Authorization
|
|
113
114
|
|
|
114
|
-
Custom actions and bulk actions
|
|
115
|
+
Custom actions and bulk actions are **allowed by default**, even when a policy is defined. This separates custom action authorization from CRUD policy. To restrict a custom action, add an `allow` rule with a condition:
|
|
115
116
|
|
|
116
117
|
```ruby
|
|
117
118
|
class UserResource < IronAdmin::Resource
|
|
@@ -125,8 +126,8 @@ class UserResource < IronAdmin::Resource
|
|
|
125
126
|
|
|
126
127
|
policy do
|
|
127
128
|
allow :read, :update
|
|
128
|
-
allow :lock #
|
|
129
|
-
allow :archive
|
|
129
|
+
allow :lock, if: ->(user) { user.admin? } # Restrict the custom action
|
|
130
|
+
allow :archive, if: ->(user) { user.admin? } # Restrict the bulk action
|
|
130
131
|
end
|
|
131
132
|
end
|
|
132
133
|
```
|
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# Building a Custom Adapter
|
|
2
|
+
|
|
3
|
+
This guide covers everything you need to build a custom IronAdmin adapter from scratch. An adapter enables IronAdmin to work with any data source — a different ORM, a REST API, a flat file, or anything else that can provide records.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
|
|
7
|
+
Every IronAdmin controller, component, and helper interacts with data exclusively through the adapter. The adapter is the **only** boundary between IronAdmin and your data source.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Controller → Resource.adapter → YourAdapter → Your Data Source
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The adapter is instantiated once per resource class with the model class as its argument:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
adapter = YourAdapter.new(Product) # Product is your model/data class
|
|
17
|
+
adapter.all # => returns all records
|
|
18
|
+
adapter.find("abc123") # => returns one record
|
|
19
|
+
adapter.filter(scope, :status, "active") # => filtered scope
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Create the adapter class
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
# lib/my_app/iron_admin/sequel_adapter.rb
|
|
28
|
+
class MyApp::IronAdmin::SequelAdapter < IronAdmin::Adapters::Base
|
|
29
|
+
# Implement all 35 methods (see reference below)
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Configure a resource to use it
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
# app/iron_admin/resources/product_resource.rb
|
|
37
|
+
module IronAdmin
|
|
38
|
+
module Resources
|
|
39
|
+
class ProductResource < IronAdmin::Resource
|
|
40
|
+
self.adapter_class = MyApp::IronAdmin::SequelAdapter
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can pass a class directly (as above). The built-in adapters (`:active_record`, `:mongoid`, `:http`) are registered in `Adapters::Registry` and can be referenced by symbol. Custom adapters should be passed as classes:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
# Pass the class directly — no registry needed
|
|
50
|
+
self.adapter_class = MyApp::IronAdmin::SequelAdapter
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Create a QueryBuilder (optional but recommended)
|
|
54
|
+
|
|
55
|
+
If your data source supports operator-based filters (`:string` and `:number` filter types), create a query builder:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
class MyApp::IronAdmin::SequelQueryBuilder < IronAdmin::Filters::BaseQueryBuilder
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def apply_string_filter
|
|
62
|
+
# Implement contains, equals, starts_with, ends_with
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def apply_number_filter
|
|
66
|
+
# Implement equals, greater_than, less_than, between
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Complete Method Reference
|
|
74
|
+
|
|
75
|
+
`Adapters::Base` defines 35 methods organized into 9 sections. All methods raise `NotImplementedError` by default except `resource_name` and `human_name` (which use `ActiveModel::Naming`).
|
|
76
|
+
|
|
77
|
+
### Schema Introspection (8 methods)
|
|
78
|
+
|
|
79
|
+
These methods let IronAdmin discover your model's structure. `FieldInferrer` calls them to auto-generate field configurations.
|
|
80
|
+
|
|
81
|
+
#### `columns` → `Array<#name, #type>`
|
|
82
|
+
|
|
83
|
+
Returns descriptors for every field/column in the model. Each object **must** respond to:
|
|
84
|
+
|
|
85
|
+
| Method | Return | Example |
|
|
86
|
+
|--------|--------|---------|
|
|
87
|
+
| `.name` | `String` | `"email"` |
|
|
88
|
+
| `.type` | `Symbol` | `:string` |
|
|
89
|
+
|
|
90
|
+
Valid type symbols (mapped by `FieldInferrer::TYPE_MAP`):
|
|
91
|
+
|
|
92
|
+
| Symbol | Rendered as |
|
|
93
|
+
|--------|------------|
|
|
94
|
+
| `:string` | Text input (auto-detects `:url` and `:email` by name pattern) |
|
|
95
|
+
| `:text` | Textarea |
|
|
96
|
+
| `:integer`, `:float`, `:decimal` | Number input (`:number`) |
|
|
97
|
+
| `:boolean` | Checkbox |
|
|
98
|
+
| `:date` | Date picker |
|
|
99
|
+
| `:datetime` | Datetime picker |
|
|
100
|
+
| `:time` | Time input |
|
|
101
|
+
| `:json`, `:jsonb` | JSON editor |
|
|
102
|
+
|
|
103
|
+
Any unrecognized type falls back to `:text`.
|
|
104
|
+
|
|
105
|
+
**Tip:** Create a `ColumnDescriptor` value object:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
ColumnDescriptor = Struct.new(:name, :type) do
|
|
109
|
+
def to_s = name
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Example (Sequel):**
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
def columns
|
|
117
|
+
model_class.db_schema.map do |name, info|
|
|
118
|
+
ColumnDescriptor.new(name.to_s, map_type(info[:type]))
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `column_names` → `Array<String>`
|
|
124
|
+
|
|
125
|
+
Flat list of column/field names as strings.
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
def column_names
|
|
129
|
+
columns.map(&:name)
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `has_column?(name)` → `Boolean`
|
|
134
|
+
|
|
135
|
+
Checks if a column/field exists. Accepts `Symbol` or `String`.
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
def has_column?(name)
|
|
139
|
+
column_names.include?(name.to_s)
|
|
140
|
+
end
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### `enums` → `Hash{String => Hash}`
|
|
144
|
+
|
|
145
|
+
Returns enum definitions. The outer key is the column name (String), the inner hash maps enum values to their storage values.
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
# Expected format:
|
|
149
|
+
{ "status" => { "active" => 0, "inactive" => 1, "archived" => 2 } }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`FieldInferrer` calls `enums.key?(name)` and `enums[name].keys` to generate select fields. Return `{}` if your data source has no enums.
|
|
153
|
+
|
|
154
|
+
#### `associations(kind = nil)` → `Array<AssociationDescriptor>`
|
|
155
|
+
|
|
156
|
+
Returns association descriptors, optionally filtered by kind. Each object **must** respond to:
|
|
157
|
+
|
|
158
|
+
| Method | Return | Notes |
|
|
159
|
+
|--------|--------|-------|
|
|
160
|
+
| `.name` | `Symbol` | Association name (e.g., `:user`) |
|
|
161
|
+
| `.klass` | `Class` | The associated model class |
|
|
162
|
+
| `.foreign_key` | `String` | Foreign key column (e.g., `"user_id"`) |
|
|
163
|
+
| `.polymorphic?` | `Boolean` | Whether this is a polymorphic association |
|
|
164
|
+
| `.foreign_type` | `String` | Polymorphic type column (e.g., `"commentable_type"`) — only called when `polymorphic?` is `true` |
|
|
165
|
+
|
|
166
|
+
`kind` is one of: `:belongs_to`, `:has_many`, `:has_one`, `:has_and_belongs_to_many`, or `nil` (return all). When `kind` is provided, `associations(kind)` must return only descriptors of that kind. IronAdmin consumers rely on `associations(kind)` for filtering — they do not call `.macro` on individual descriptors.
|
|
167
|
+
|
|
168
|
+
**Tip:** Create an `AssociationWrapper` class that tracks the kind internally and use it to filter in `associations(kind)`.
|
|
169
|
+
|
|
170
|
+
Return `[]` if your data source has no associations.
|
|
171
|
+
|
|
172
|
+
#### `association(name)` → `AssociationDescriptor | nil`
|
|
173
|
+
|
|
174
|
+
Returns a single association descriptor by name, or `nil` if not found.
|
|
175
|
+
|
|
176
|
+
#### `attachments` → `Hash`
|
|
177
|
+
|
|
178
|
+
Returns file attachment descriptors. Each value must respond to `.macro` returning `:has_one_attached` or `:has_many_attached`. This is ActiveStorage-specific — return `{}` for non-Rails data sources.
|
|
179
|
+
|
|
180
|
+
#### `rich_text_attributes` → `Array<Symbol>`
|
|
181
|
+
|
|
182
|
+
Returns ActionText rich text attribute names. Each name starts with `rich_text_` (e.g., `:rich_text_content`). Return `[]` for non-Rails data sources.
|
|
183
|
+
|
|
184
|
+
### Naming (3 methods)
|
|
185
|
+
|
|
186
|
+
#### `resource_name` → `String`
|
|
187
|
+
|
|
188
|
+
**Implemented in Base.** Returns the URL-friendly plural name (e.g., `"users"`). Uses `model_class.model_name.plural`. Override only if your model doesn't include `ActiveModel::Naming`.
|
|
189
|
+
|
|
190
|
+
#### `human_name` → `String`
|
|
191
|
+
|
|
192
|
+
**Implemented in Base.** Returns the human-readable name (e.g., `"User"`). Uses `model_class.model_name.human`. Override only if your model doesn't include `ActiveModel::Naming`.
|
|
193
|
+
|
|
194
|
+
#### `table_name` → `String | nil`
|
|
195
|
+
|
|
196
|
+
Returns the storage name (table, collection, endpoint path). Return `nil` if not applicable.
|
|
197
|
+
|
|
198
|
+
### Query Building (10 methods)
|
|
199
|
+
|
|
200
|
+
These methods build and manipulate query scopes. A "scope" is any chainable query object — an `ActiveRecord::Relation`, a `Mongoid::Criteria`, or your own query builder.
|
|
201
|
+
|
|
202
|
+
#### `all` → `Scope`
|
|
203
|
+
|
|
204
|
+
Returns a base scope representing all records.
|
|
205
|
+
|
|
206
|
+
#### `find(id)` → `Record`
|
|
207
|
+
|
|
208
|
+
Finds a record by primary key. **Must raise `IronAdmin::RecordNotFound`** when the record doesn't exist. Wrap your ORM's native not-found exception:
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
def find(id)
|
|
212
|
+
model_class.find(id)
|
|
213
|
+
rescue MyOrm::NotFoundError => e
|
|
214
|
+
raise IronAdmin::RecordNotFound, e.message
|
|
215
|
+
end
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### `find_by(attrs)` → `Record | nil`
|
|
219
|
+
|
|
220
|
+
Finds a record by attributes hash. Returns `nil` when not found (does **not** raise).
|
|
221
|
+
|
|
222
|
+
#### `filter(scope, column, value)` → `Scope`
|
|
223
|
+
|
|
224
|
+
Filters a scope by a column value. Must handle these value types:
|
|
225
|
+
|
|
226
|
+
| Value type | Expected behavior |
|
|
227
|
+
|-----------|-------------------|
|
|
228
|
+
| Scalar (String, Integer, etc.) | Exact match |
|
|
229
|
+
| `Array` | IN / any-of match |
|
|
230
|
+
| `Range` | Between (may be beginless or endless) |
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
def filter(scope, column, value)
|
|
234
|
+
case value
|
|
235
|
+
when Array then scope.where(column => value) # IN clause
|
|
236
|
+
when Range then scope.where(column => value) # BETWEEN
|
|
237
|
+
else scope.where(column => value) # exact match
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `order_by(scope, column, direction)` → `Scope`
|
|
243
|
+
|
|
244
|
+
Orders a scope. `direction` is `:asc` or `:desc`.
|
|
245
|
+
|
|
246
|
+
#### `limit(scope, max)` → `Scope`
|
|
247
|
+
|
|
248
|
+
Limits the scope to `max` records.
|
|
249
|
+
|
|
250
|
+
#### `preload(scope, association_names)` → `Scope`
|
|
251
|
+
|
|
252
|
+
Eager-loads associations to prevent N+1 queries. `association_names` is an `Array<Symbol>`. If your data source doesn't support eager loading, return the scope unmodified.
|
|
253
|
+
|
|
254
|
+
#### `distinct_values(column)` → `Array`
|
|
255
|
+
|
|
256
|
+
Returns sorted, unique, non-nil values for a column. Used to populate filter dropdowns.
|
|
257
|
+
|
|
258
|
+
#### `pluck(scope, column)` → `Array`
|
|
259
|
+
|
|
260
|
+
Extracts raw values for a single column from a scope.
|
|
261
|
+
|
|
262
|
+
#### `count(scope = nil)` → `Integer`
|
|
263
|
+
|
|
264
|
+
Counts records. When `scope` is `nil`, count all records.
|
|
265
|
+
|
|
266
|
+
### Search (2 methods)
|
|
267
|
+
|
|
268
|
+
#### `search_column(scope, column, query)` → `Scope`
|
|
269
|
+
|
|
270
|
+
Searches a single column for a substring match (case-insensitive). The `query` string comes from user input — **always escape it** to prevent injection:
|
|
271
|
+
|
|
272
|
+
- SQL: Use parameterized `LIKE`/`ILIKE` with `sanitize_like`
|
|
273
|
+
- MongoDB: Use `Regexp.escape` before building regex
|
|
274
|
+
- HTTP API: URL-encode the query
|
|
275
|
+
|
|
276
|
+
#### `search_columns(scope, columns, query)` → `Scope`
|
|
277
|
+
|
|
278
|
+
Searches multiple columns with OR logic. Same escaping rules apply.
|
|
279
|
+
|
|
280
|
+
### CRUD (4 methods)
|
|
281
|
+
|
|
282
|
+
#### `build(attrs = {})` → `Record`
|
|
283
|
+
|
|
284
|
+
Creates a new unsaved record with the given attributes.
|
|
285
|
+
|
|
286
|
+
#### `save(record)` → `Boolean`
|
|
287
|
+
|
|
288
|
+
Persists a record. Returns `true` on success, `false` on validation failure.
|
|
289
|
+
|
|
290
|
+
#### `update(record, attrs)` → `Boolean`
|
|
291
|
+
|
|
292
|
+
Updates a record's attributes. Returns `true` on success, `false` on validation failure.
|
|
293
|
+
|
|
294
|
+
#### `destroy!(record)` → `void`
|
|
295
|
+
|
|
296
|
+
Permanently deletes a record. Should raise on failure (bang method).
|
|
297
|
+
|
|
298
|
+
### Transactions (1 method)
|
|
299
|
+
|
|
300
|
+
#### `transaction(&block)` → `Object`
|
|
301
|
+
|
|
302
|
+
Wraps a block in an atomic transaction. If your data source doesn't support transactions, simply `yield`:
|
|
303
|
+
|
|
304
|
+
```ruby
|
|
305
|
+
def transaction
|
|
306
|
+
yield
|
|
307
|
+
end
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Scope Manipulation (1 method)
|
|
311
|
+
|
|
312
|
+
#### `unscope_column(scope, column)` → `Scope`
|
|
313
|
+
|
|
314
|
+
Removes a WHERE condition on a specific column from a scope. Used by the soft-delete feature to bypass the default `deleted_at IS NULL` filter.
|
|
315
|
+
|
|
316
|
+
If your scope object supports `unscope`, use it. Otherwise, rebuild the scope without the column:
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
def unscope_column(scope, column)
|
|
320
|
+
# Rebuild scope excluding the column from conditions
|
|
321
|
+
end
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Batch (1 method)
|
|
325
|
+
|
|
326
|
+
#### `find_each(scope, &block)` → `void`
|
|
327
|
+
|
|
328
|
+
Iterates all records in memory-efficient batches. Used by CSV export. If your data source doesn't support batching, fall back to `.each`:
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
def find_each(scope, &block)
|
|
332
|
+
scope.each(&block)
|
|
333
|
+
end
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Adapter-Agnostic Interface (5 methods)
|
|
337
|
+
|
|
338
|
+
These methods bridge differences between ORMs so controllers remain adapter-agnostic.
|
|
339
|
+
|
|
340
|
+
#### `record_changes(record)` → `Hash`
|
|
341
|
+
|
|
342
|
+
Returns the changes hash after a save/update operation. Used by audit logging.
|
|
343
|
+
|
|
344
|
+
| ORM | Implementation |
|
|
345
|
+
|-----|---------------|
|
|
346
|
+
| ActiveRecord | `record.saved_changes` |
|
|
347
|
+
| Mongoid | `record.previous_changes` |
|
|
348
|
+
| HTTP API | `{}` (or track changes client-side) |
|
|
349
|
+
|
|
350
|
+
#### `wrap_rollback(&block)` → `void`
|
|
351
|
+
|
|
352
|
+
Executes a block and converts `IronAdmin::Rollback` to the adapter-native rollback mechanism. This is called **inside** `transaction`:
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
# Controller does:
|
|
356
|
+
adapter.transaction do
|
|
357
|
+
adapter.wrap_rollback do
|
|
358
|
+
# ... action code ...
|
|
359
|
+
raise IronAdmin::Rollback if result == false
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
| ORM | Implementation |
|
|
365
|
+
|-----|---------------|
|
|
366
|
+
| ActiveRecord | Rescue `IronAdmin::Rollback`, re-raise as `ActiveRecord::Rollback` |
|
|
367
|
+
| Mongoid | Rescue `IronAdmin::Rollback`, return `nil` |
|
|
368
|
+
| No transactions | Rescue `IronAdmin::Rollback`, return `nil` |
|
|
369
|
+
|
|
370
|
+
#### `query_builder_class` → `Class`
|
|
371
|
+
|
|
372
|
+
Returns the `BaseQueryBuilder` subclass for operator-based filters (`:string` and `:number` filter types). If you don't support operator filters, create a no-op builder:
|
|
373
|
+
|
|
374
|
+
```ruby
|
|
375
|
+
class NoOpQueryBuilder < IronAdmin::Filters::BaseQueryBuilder
|
|
376
|
+
private
|
|
377
|
+
|
|
378
|
+
def apply_string_filter = @scope
|
|
379
|
+
def apply_number_filter = @scope
|
|
380
|
+
end
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### `pagy_method` → `Symbol`
|
|
384
|
+
|
|
385
|
+
Returns the Pagy backend method name used for pagination.
|
|
386
|
+
|
|
387
|
+
| ORM | Value |
|
|
388
|
+
|-----|-------|
|
|
389
|
+
| ActiveRecord | `:pagy` |
|
|
390
|
+
| Mongoid | `:pagy_mongoid` |
|
|
391
|
+
| Custom | `:pagy` (default) or implement a custom Pagy backend |
|
|
392
|
+
|
|
393
|
+
#### `cast_boolean(value)` → `Boolean`
|
|
394
|
+
|
|
395
|
+
Casts a string form value (`"true"`, `"false"`, `"1"`, `"0"`) to a Ruby boolean. Used by filter params.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## QueryBuilder Integration
|
|
400
|
+
|
|
401
|
+
If your data source supports operator-based string and number filters, create a `BaseQueryBuilder` subclass.
|
|
402
|
+
|
|
403
|
+
### String operators
|
|
404
|
+
|
|
405
|
+
| Operator | Behavior |
|
|
406
|
+
|----------|----------|
|
|
407
|
+
| `contains` | Substring match (case-insensitive) |
|
|
408
|
+
| `equals` | Exact match |
|
|
409
|
+
| `starts_with` | Prefix match |
|
|
410
|
+
| `ends_with` | Suffix match |
|
|
411
|
+
|
|
412
|
+
### Number operators
|
|
413
|
+
|
|
414
|
+
| Operator | Behavior |
|
|
415
|
+
|----------|----------|
|
|
416
|
+
| `equals` | Exact numeric match |
|
|
417
|
+
| `greater_than` | Greater than |
|
|
418
|
+
| `less_than` | Less than |
|
|
419
|
+
| `between` | Range (inclusive, uses `@value` and `@upper_value`) |
|
|
420
|
+
|
|
421
|
+
### Example (Sequel)
|
|
422
|
+
|
|
423
|
+
```ruby
|
|
424
|
+
class SequelQueryBuilder < IronAdmin::Filters::BaseQueryBuilder
|
|
425
|
+
private
|
|
426
|
+
|
|
427
|
+
def apply_string_filter
|
|
428
|
+
return @scope unless STRING_OPS.include?(@op)
|
|
429
|
+
|
|
430
|
+
col = ::Sequel[@filter[:name]]
|
|
431
|
+
case @op
|
|
432
|
+
when "contains" then @scope.where(col.ilike("%#{escape(@value)}%"))
|
|
433
|
+
when "equals" then @scope.where(@filter[:name] => @value)
|
|
434
|
+
when "starts_with" then @scope.where(col.ilike("#{escape(@value)}%"))
|
|
435
|
+
when "ends_with" then @scope.where(col.ilike("%#{escape(@value)}"))
|
|
436
|
+
else @scope
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def apply_number_filter
|
|
441
|
+
return @scope unless NUMBER_OPS.include?(@op)
|
|
442
|
+
|
|
443
|
+
num = cast_number(@value)
|
|
444
|
+
return @scope unless num
|
|
445
|
+
|
|
446
|
+
case @op
|
|
447
|
+
when "equals" then @scope.where(@filter[:name] => num)
|
|
448
|
+
when "greater_than" then @scope.where { |o| o.send(@filter[:name]) > num }
|
|
449
|
+
when "less_than" then @scope.where { |o| o.send(@filter[:name]) < num }
|
|
450
|
+
when "between" then apply_between(num)
|
|
451
|
+
else @scope
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def apply_between(num)
|
|
456
|
+
upper = cast_number(@upper_value)
|
|
457
|
+
return @scope unless upper
|
|
458
|
+
|
|
459
|
+
@scope.where(@filter[:name] => num..upper)
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def escape(value)
|
|
463
|
+
value.gsub(/[%_\\]/) { |m| "\\#{m}" }
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The `cast_number` method is inherited from `BaseQueryBuilder` — it handles integer/float parsing and returns `nil` for invalid values.
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## Testing Your Adapter
|
|
473
|
+
|
|
474
|
+
Follow the same patterns used by the built-in adapter specs. Your test file should mirror `spec/lib/iron_admin/adapters/active_record_spec.rb`.
|
|
475
|
+
|
|
476
|
+
### Unit tests with doubles (no database required)
|
|
477
|
+
|
|
478
|
+
For adapters that wrap an external service or unavailable ORM, use test doubles:
|
|
479
|
+
|
|
480
|
+
```ruby
|
|
481
|
+
RSpec.describe MyAdapter do
|
|
482
|
+
subject(:adapter) { described_class.new(model_class) }
|
|
483
|
+
|
|
484
|
+
let(:model_class) do
|
|
485
|
+
double("Model",
|
|
486
|
+
fields: { "name" => double(name: "name", type: String) },
|
|
487
|
+
model_name: double(plural: "products", human: "Product"),
|
|
488
|
+
# ... stub all methods your adapter calls
|
|
489
|
+
)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
describe "#columns" do
|
|
493
|
+
it "returns an array" do
|
|
494
|
+
expect(adapter.columns).to be_an(Array)
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it "returns descriptors with name and type" do
|
|
498
|
+
expect(adapter.columns.first).to respond_to(:name)
|
|
499
|
+
expect(adapter.columns.first).to respond_to(:type)
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
describe "#find" do
|
|
504
|
+
it "raises IronAdmin::RecordNotFound for missing records" do
|
|
505
|
+
allow(model_class).to receive(:find).and_raise(SomeNotFoundError)
|
|
506
|
+
expect { adapter.find("bad") }.to raise_error(IronAdmin::RecordNotFound)
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# ... test all 35 methods
|
|
511
|
+
end
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Integration tests with a real data source
|
|
515
|
+
|
|
516
|
+
If possible, also test with real data:
|
|
517
|
+
|
|
518
|
+
```ruby
|
|
519
|
+
RSpec.describe MyAdapter, :integration do
|
|
520
|
+
subject(:adapter) { described_class.new(RealModel) }
|
|
521
|
+
|
|
522
|
+
describe "#filter" do
|
|
523
|
+
it "filters by exact value" do
|
|
524
|
+
RealModel.create!(name: "Alice", status: "active")
|
|
525
|
+
RealModel.create!(name: "Bob", status: "inactive")
|
|
526
|
+
result = adapter.filter(adapter.all, :status, "active")
|
|
527
|
+
expect(result.count).to eq(1)
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### BetterSpecs conventions
|
|
534
|
+
|
|
535
|
+
Follow [BetterSpecs](https://www.betterspecs.org/) as required by this project:
|
|
536
|
+
|
|
537
|
+
- `describe "#method_name"` for each method
|
|
538
|
+
- `context "when ..."` for conditional behavior
|
|
539
|
+
- One expectation per `it` block
|
|
540
|
+
- Use `subject(:adapter)` and `let` for setup
|
|
541
|
+
- Meaningful descriptions that read as sentences
|
|
542
|
+
|
|
543
|
+
### Coverage requirements
|
|
544
|
+
|
|
545
|
+
SimpleCov enforces **80% minimum per file**. Ensure your adapter and query builder files have adequate test coverage.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Checklist
|
|
550
|
+
|
|
551
|
+
Use this checklist when building a new adapter:
|
|
552
|
+
|
|
553
|
+
### Setup
|
|
554
|
+
- [ ] Create adapter class inheriting from `IronAdmin::Adapters::Base`
|
|
555
|
+
- [ ] Create value objects (`ColumnDescriptor`, `AssociationWrapper`) if needed
|
|
556
|
+
- [ ] Create `QueryBuilder` subclass (or use `NoOpQueryBuilder`)
|
|
557
|
+
|
|
558
|
+
### Schema Introspection
|
|
559
|
+
- [ ] `columns` — returns `Array<#name, #type>` with valid type symbols
|
|
560
|
+
- [ ] `column_names` — returns `Array<String>`
|
|
561
|
+
- [ ] `has_column?(name)` — handles both Symbol and String input
|
|
562
|
+
- [ ] `enums` — returns `Hash{String => Hash}` or `{}`
|
|
563
|
+
- [ ] `associations(kind)` — returns filtered `Array<AssociationDescriptor>` or `[]`
|
|
564
|
+
- [ ] `association(name)` — returns descriptor or `nil`
|
|
565
|
+
- [ ] `attachments` — returns `Hash` or `{}`
|
|
566
|
+
- [ ] `rich_text_attributes` — returns `Array<Symbol>` or `[]`
|
|
567
|
+
|
|
568
|
+
### Naming
|
|
569
|
+
- [ ] `table_name` — returns `String` or `nil`
|
|
570
|
+
- [ ] Verify `resource_name` and `human_name` work (inherited from Base)
|
|
571
|
+
|
|
572
|
+
### Query Building
|
|
573
|
+
- [ ] `all` — returns a chainable scope
|
|
574
|
+
- [ ] `find(id)` — raises `IronAdmin::RecordNotFound` on miss
|
|
575
|
+
- [ ] `find_by(attrs)` — returns `nil` on miss (does not raise)
|
|
576
|
+
- [ ] `filter(scope, column, value)` — handles scalars, Arrays, and Ranges
|
|
577
|
+
- [ ] `order_by(scope, column, direction)` — `:asc` and `:desc`
|
|
578
|
+
- [ ] `limit(scope, max)` — returns limited scope
|
|
579
|
+
- [ ] `preload(scope, names)` — eager loads or returns scope unchanged
|
|
580
|
+
- [ ] `distinct_values(column)` — sorted, compact, unique
|
|
581
|
+
- [ ] `pluck(scope, column)` — raw column values
|
|
582
|
+
- [ ] `count(scope)` — defaults to `all` when scope is `nil`
|
|
583
|
+
|
|
584
|
+
### Search
|
|
585
|
+
- [ ] `search_column(scope, column, query)` — case-insensitive, escaped
|
|
586
|
+
- [ ] `search_columns(scope, columns, query)` — OR logic across columns
|
|
587
|
+
|
|
588
|
+
### CRUD
|
|
589
|
+
- [ ] `build(attrs)` — unsaved record
|
|
590
|
+
- [ ] `save(record)` — returns boolean
|
|
591
|
+
- [ ] `update(record, attrs)` — returns boolean
|
|
592
|
+
- [ ] `destroy!(record)` — raises on failure
|
|
593
|
+
|
|
594
|
+
### Transactions & Scope
|
|
595
|
+
- [ ] `transaction(&block)` — atomic or yield
|
|
596
|
+
- [ ] `unscope_column(scope, column)` — removes condition
|
|
597
|
+
- [ ] `find_each(scope, &block)` — batched or `.each`
|
|
598
|
+
|
|
599
|
+
### Adapter-Agnostic
|
|
600
|
+
- [ ] `record_changes(record)` — returns changes hash
|
|
601
|
+
- [ ] `wrap_rollback(&block)` — catches `IronAdmin::Rollback`
|
|
602
|
+
- [ ] `query_builder_class` — returns your QueryBuilder subclass
|
|
603
|
+
- [ ] `pagy_method` — returns `:pagy` or custom
|
|
604
|
+
- [ ] `cast_boolean(value)` — string to boolean
|
|
605
|
+
|
|
606
|
+
### Testing
|
|
607
|
+
- [ ] Unit specs for all 35 methods
|
|
608
|
+
- [ ] Edge cases: nil values, empty arrays, missing records
|
|
609
|
+
- [ ] `find` raises `IronAdmin::RecordNotFound`
|
|
610
|
+
- [ ] `find_by` returns `nil` (not raises)
|
|
611
|
+
- [ ] QueryBuilder specs for all operators
|
|
612
|
+
- [ ] 80%+ coverage per file
|
|
613
|
+
|
|
614
|
+
### Documentation
|
|
615
|
+
- [ ] Update `CHANGELOG.md` under `[Unreleased]`
|
|
616
|
+
- [ ] Update `docs/guides/extending.md` if adding a built-in adapter
|
|
617
|
+
- [ ] Add setup instructions for the new data source
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## Reference: Built-in Adapters
|
|
622
|
+
|
|
623
|
+
| Adapter | Data source | Key differences |
|
|
624
|
+
|---------|-------------|----------------|
|
|
625
|
+
| `ActiveRecord` | SQL databases (PostgreSQL, MySQL, SQLite) | Uses `LIKE`/`ILIKE` for search, `ActiveRecord::Base.transaction`, `scope.unscope(where:)` |
|
|
626
|
+
| `Mongoid` | MongoDB | Uses `$regex` for search, `scope.any_of` for OR, `scope.in` for arrays, `scope.selector` for unscope |
|
|
627
|
+
|
|
628
|
+
Study `lib/iron_admin/adapters/active_record.rb` (simplest) and `lib/iron_admin/adapters/mongoid.rb` (most complex) as reference implementations.
|