From d9978052703e87d251eb97f32cf304ff86c071cd Mon Sep 17 00:00:00 2001 From: Kaspar Vollenweider Date: Sat, 15 Feb 2025 22:09:42 +0100 Subject: [PATCH] feat(ransack_allow): Add ransackable class method definition helpers Add helper methods for defining Ransack-allowed elements: - `ransack_allow_attributes :column_a, :column_b` - `ransack_allow_associations :association_a, :association_b` - `ransack_allow_scopes :scope_a, :scope_b` These helpers provide a more convenient and cleaner way to define the ransackable_* class methods. They use define_singleton_method internally, maintaining full compatibility with Ransack's existing functionality. --- lib/ransack/adapters/active_record/base.rb | 45 +++++++++++++++++++ .../adapters/active_record/base_spec.rb | 27 +++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/ransack/adapters/active_record/base.rb b/lib/ransack/adapters/active_record/base.rb index 15a4cd66..d3d7dfbf 100644 --- a/lib/ransack/adapters/active_record/base.rb +++ b/lib/ransack/adapters/active_record/base.rb @@ -9,6 +9,51 @@ def self.extended(base) class_attribute :_ransack_aliases self._ransackers ||= {} self._ransack_aliases ||= {} + + # Allow attributes to be searched by ransack + # + # Defines the ransackable_attributes class method. + # @see Base.ransackable_attributes + # @param [Array] attributes the attributes to be allowed + # @example allow column_a and column_b to be searched + # class MyModel < ApplicationRecord + # ransack_allow_attributes :column_a, :column_b + # end + def self.ransack_allow_attributes(*attributes) + define_singleton_method(:ransackable_attributes) do |auth_object = nil| + attributes.map(&:to_s) + end + end + + # Allow associations to be searched by ransack + # + # Defines the ransackable_associations class method. + # @see Base.ransackable_associations + # @param [Array] associations the associations to be allowed + # @example allow association_a and association_b to be searched + # class MyModel < ApplicationRecord + # ransack_allow_associations :association_a, :association_b + # end + def self.ransack_allow_associations(*associations) + define_singleton_method(:ransackable_associations) do |auth_object = nil| + associations.map(&:to_s) + end + end + + # Allow scopes to be searched by ransack + # + # Defines the ransackable_scopes class method. + # @see Base.ransackable_scopes + # @param [Array] scopes the scopes to be allowed + # @example allow scope_a and scope_b to be used with ransack + # class MyModel < ApplicationRecord + # ransack_allow_scopes :scope_a, :scope_b + # end + def self.ransack_allow_scopes(*scopes) + define_singleton_method(:ransackable_scopes) do |auth_object = nil| + scopes.map(&:to_s) + end + end end end diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index a6b10cfa..af70edb9 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -710,6 +710,15 @@ def self.simple_escaping? end end + describe '.ransack_allow_attributes' do + subject { Article } + + it 'has a class method returning an array with title and subject_header elements' do + subject.ransack_allow_attributes :title, :subject_header + expect(subject.ransackable_attributes).to match_array(%w[title subject_header]) + end + end + describe '#ransortable_attributes' do context 'when auth_object is nil' do subject { Person.ransortable_attributes } @@ -773,12 +782,30 @@ def self.simple_escaping? end end + describe '.ransack_allow_associations' do + subject { Article } + + it 'has a class method returning an array with string "person" element' do + subject.ransack_allow_associations :person + expect(subject.ransackable_associations).to match_array(%w[person]) + end + end + describe '#ransackable_scopes' do subject { Person.ransackable_scopes } it { should eq [] } end + describe '.ransack_allow_scopes' do + subject { Article } + + it 'has a class method returning an array with string "latest_comment_cont" element' do + subject.ransack_allow_scopes :latest_comment_cont + expect(subject.ransackable_scopes).to match_array(%w[latest_comment_cont]) + end + end + describe '#ransackable_scopes_skip_sanitize_args' do subject { Person.ransackable_scopes_skip_sanitize_args }