From 6a2863efce81bb0e3d4f9419c622a68f1dd91d2a Mon Sep 17 00:00:00 2001 From: Alexey Vasiliev Date: Fri, 13 Sep 2024 23:54:52 +0300 Subject: [PATCH] Correct usage ransack_alias in forms --- .github/workflows/cronjob.yml | 6 ++--- .github/workflows/deploy.yml | 6 ++--- .github/workflows/rubocop.yml | 2 +- .github/workflows/test-deploy.yml | 4 +-- .github/workflows/test.yml | 8 +++--- lib/ransack/nodes/condition.rb | 26 ++++++++++++------- lib/ransack/nodes/grouping.rb | 21 +++++++++++++-- lib/ransack/search.rb | 9 +++++++ .../adapters/active_record/base_spec.rb | 21 +++++++++++++++ spec/ransack/nodes/condition_spec.rb | 5 +++- spec/ransack/search_spec.rb | 8 ++++++ 11 files changed, 90 insertions(+), 26 deletions(-) diff --git a/.github/workflows/cronjob.yml b/.github/workflows/cronjob.yml index 941d3a5b..ccb0e3d7 100644 --- a/.github/workflows/cronjob.yml +++ b/.github/workflows/cronjob.yml @@ -16,7 +16,7 @@ jobs: DB: sqlite3 RAILS: main steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -39,7 +39,7 @@ jobs: MYSQL_USERNAME: root MYSQL_PASSWORD: root steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -85,7 +85,7 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 661c39c7..fb001fb4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,9 +12,9 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 16 cache: yarn @@ -29,7 +29,7 @@ jobs: working-directory: docs - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/build diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 7d68b9f6..ce26b50e 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/test-deploy.yml b/.github/workflows/test-deploy.yml index 8e2c0a1a..a353d664 100644 --- a/.github/workflows/test-deploy.yml +++ b/.github/workflows/test-deploy.yml @@ -12,9 +12,9 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 16 cache: yarn diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0025eb93..66d31d77 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: DB: sqlite3 RAILS: ${{ matrix.rails }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -52,7 +52,7 @@ jobs: MYSQL_USERNAME: root MYSQL_PASSWORD: root steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -103,7 +103,7 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -118,7 +118,7 @@ jobs: bug-report-templates: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/lib/ransack/nodes/condition.rb b/lib/ransack/nodes/condition.rb index af69c037..4499a8a0 100644 --- a/lib/ransack/nodes/condition.rb +++ b/lib/ransack/nodes/condition.rb @@ -1,16 +1,16 @@ module Ransack module Nodes class Condition < Node - i18n_word :attribute, :predicate, :combinator, :value + i18n_word :attribute, :predicate, :combinator, :value, :name i18n_alias a: :attribute, p: :predicate, - m: :combinator, v: :value + m: :combinator, v: :value, n: :name - attr_accessor :predicate + attr_accessor :predicate, :name class << self - def extract(context, key, values) + def extract(context, name, values) attributes, predicate, combinator = - extract_values_for_condition(key, context) + extract_values_for_condition(name, context) if attributes.size > 0 && predicate condition = self.new(context) @@ -18,7 +18,8 @@ def extract(context, key, values) a: attributes, p: predicate.name, m: combinator, - v: predicate.wants_array ? Array(values) : [values] + v: predicate.wants_array ? Array(values) : [values], + n: name ) # TODO: Figure out what to do with multiple types of attributes, # if anything. Tempted to go with "garbage in, garbage out" here. @@ -127,6 +128,9 @@ def combinator=(val) alias :m= :combinator= alias :m :combinator + alias :n= :name= + alias :n :name + # == build_attribute # # This method was originally called from Nodes::Grouping#new_condition @@ -171,7 +175,7 @@ def value def build(params) params.with_indifferent_access.each do |key, value| - if key.match(/^(a|v|p|m)$/) + if key.match(/^(a|v|p|m|n)$/) self.send("#{key}=", value) end end @@ -193,12 +197,13 @@ def eql?(other) self.attributes == other.attributes && self.predicate == other.predicate && self.values == other.values && - self.combinator == other.combinator + self.combinator == other.combinator && + self.name == other.name end alias :== :eql? def hash - [attributes, predicate, values, combinator].hash + [attributes, predicate, values, combinator, name].hash end def predicate_name=(name) @@ -271,7 +276,8 @@ def inspect ['attributes'.freeze, a.try(:map, &:name)], ['predicate'.freeze, p], [Constants::COMBINATOR, m], - ['values'.freeze, v.try(:map, &:value)] + ['values'.freeze, v.try(:map, &:value)], + ['name'.freeze, n] ] .reject { |e| e[1].blank? } .map { |v| "#{v[0]}: #{v[1]}" } diff --git a/lib/ransack/nodes/grouping.rb b/lib/ransack/nodes/grouping.rb index 1bf70550..0512219b 100644 --- a/lib/ransack/nodes/grouping.rb +++ b/lib/ransack/nodes/grouping.rb @@ -49,14 +49,23 @@ def conditions=(conditions) alias :c= :conditions= def [](key) - conditions.detect { |c| c.key == key.to_s } + conditions.detect do |c| + matched_condition(c, key) + end end def []=(key, value) - conditions.reject! { |c| c.key == key.to_s } + conditions.reject! do |c| + matched_condition(c, key) + end + self.conditions << value end + def matched_condition(c, key) + c.name == key.to_s + end + def values conditions + groupings end @@ -107,6 +116,14 @@ def groupings=(groupings) end alias :g= :groupings= + def respond_to_missing?(method_id, include_private = false) + method_name = method_id.to_s.dup + writer = method_name.sub!(/\=$/, ''.freeze) + return true if attribute_method?(method_name) + + super + end + def method_missing(method_id, *args) method_name = method_id.to_s.dup writer = method_name.sub!(/\=$/, ''.freeze) diff --git a/lib/ransack/search.rb b/lib/ransack/search.rb index a8bf95f8..512c54d9 100644 --- a/lib/ransack/search.rb +++ b/lib/ransack/search.rb @@ -99,6 +99,15 @@ def new_sort(opts = {}) Nodes::Sort.new(@context).build(opts) end + def respond_to_missing?(method_id, include_private = false) + method_name = method_id.to_s + getter_name = method_name.sub(/=$/, ''.freeze) + return true if base.attribute_method?(getter_name) + return true if @context.ransackable_scope?(getter_name, @context.object) + + super + end + def method_missing(method_id, *args) method_name = method_id.to_s getter_name = method_name.sub(/=$/, ''.freeze) diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index d41cd6d0..a9a567f3 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -239,6 +239,27 @@ module ActiveRecord expect(s.result.to_a).to eq [] end + it 'return alias correctly from search' do + s = Person.ransack(term_cont: 'atlo') + expect(s.term_cont).to eq 'atlo' + expect(s.name_or_email_cont).to eq nil + + s = Person.ransack(daddy_cont: 'babi') + expect(s.daddy_cont).to eq 'babi' + expect(s.parent_name_cont).to eq nil + + s = Person.ransack( + term_cont: 'atlo', + name_or_email_cont: 'different' + ) + expect(s.term_cont).to eq 'atlo' + expect(s.name_or_email_cont).to eq 'different' + expect(s.result.to_sql).to include(/("|`)people("|`)\.("|`)name("|`) I?LIKE '%different%'/i) + expect(s.result.to_sql).to include(/("|`)people("|`)\.("|`)email("|`) I?LIKE '%different%'/i) + expect(s.result.to_sql).to include(/("|`)people("|`)\.("|`)name("|`) I?LIKE '%atlo%'/i) + expect(s.result.to_sql).to include(/("|`)people("|`)\.("|`)email("|`) I?LIKE '%atlo%'/i) + end + it 'also works with associations' do dad = Person.create!(name: 'Birdman') son = Person.create!(name: 'Weezy', parent: dad) diff --git a/spec/ransack/nodes/condition_spec.rb b/spec/ransack/nodes/condition_spec.rb index 29596cac..4bba3187 100644 --- a/spec/ransack/nodes/condition_spec.rb +++ b/spec/ransack/nodes/condition_spec.rb @@ -95,7 +95,10 @@ module Nodes Ransack.configure { |c| c.default_predicate = 'eq' } end - specify { expect(subject).to eq Condition.extract(Context.for(Person), 'full_name_eq', Person.first.name) } + specify do + expect(subject).not_to be_nil + expect(subject.predicate.name).to eq 'eq' + end end end end diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 6426a20a..a5aa89e3 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -689,6 +689,14 @@ def remove_quotes_and_backticks(str) ] expect(@s.groupings.first.children_name_eq).to eq 'Ernie' end + + it 'respond_to? method_missing' do + @s.groupings = [ + { m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' } + ] + expect(@s.groupings.first.respond_to?(:children_name_eq)).to eq true + expect(@s.groupings.first.method(:children_name_eq)).to be_truthy + end end end end