Skip to content

Commit

Permalink
Merge pull request #623 from rzane/ransack-alias
Browse files Browse the repository at this point in the history
Allow creating aliases for ransack attributes.
  • Loading branch information
jonatack committed Dec 19, 2015
2 parents 2f256ae + e712ff1 commit 1de3453
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 6 deletions.
10 changes: 8 additions & 2 deletions lib/ransack/adapters/active_record/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ def self.extended(base)
alias :search :ransack unless base.respond_to? :search
base.class_eval do
class_attribute :_ransackers
class_attribute :_ransack_aliases
self._ransackers ||= {}
self._ransack_aliases ||= {}
end
end

Expand All @@ -20,15 +22,19 @@ def ransacker(name, opts = {}, &block)
.new(self, name, opts, &block)
end

def ransack_alias(new_name, old_name)
self._ransack_aliases.store(new_name.to_s, old_name.to_s)
end

# Ransackable_attributes, by default, returns all column names
# and any defined ransackers as an array of strings.
# For overriding with a whitelist array of strings.
#
def ransackable_attributes(auth_object = nil)
if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
column_names + _ransackers.keys + attribute_aliases.keys
column_names + _ransackers.keys + _ransack_aliases.keys + attribute_aliases.keys
else
column_names + _ransackers.keys
column_names + _ransackers.keys + _ransack_aliases.keys
end
end

Expand Down
14 changes: 13 additions & 1 deletion lib/ransack/adapters/mongoid/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ def quote_column_name name
end

module ClassMethods
def _ransack_aliases
@_ransack_aliases ||= {}
end

def _ransack_aliases=(value)
@_ransack_aliases = value
end

def _ransackers
@_ransackers ||= {}
end
Expand All @@ -49,13 +57,17 @@ def ransack(params = {}, options = {})

alias_method :search, :ransack

def ransack_alias(new_name, old_name)
self._ransack_aliases.store(new_name.to_s, old_name.to_s)
end

def ransacker(name, opts = {}, &block)
self._ransackers = _ransackers.merge name.to_s => Ransacker
.new(self, name, opts, &block)
end

def all_ransackable_attributes
['id'] + column_names.select { |c| c != '_id' } + _ransackers.keys
['id'] + column_names.select { |c| c != '_id' } + _ransackers.keys + _ransack_aliases.keys
end

def ransackable_attributes(auth_object = nil)
Expand Down
4 changes: 4 additions & 0 deletions lib/ransack/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ def unpolymorphize_association(str)
end
end

def ransackable_alias(str)
klass._ransack_aliases.fetch(str, str)
end

def ransackable_attribute?(str, klass)
klass.ransackable_attributes(auth_object).include?(str) ||
klass.ransortable_attributes(auth_object).include?(str)
Expand Down
9 changes: 6 additions & 3 deletions lib/ransack/nodes/condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ class Condition < Node

class << self
def extract(context, key, values)
attributes, predicate = extract_attributes_and_predicate(key, context)
attributes, predicate, combinator = extract_attributes_and_predicate(key, context)

if attributes.size > 0 && predicate
combinator = key.match(/_(or|and)_/) ? $1 : nil
condition = self.new(context)
condition.build(
:a => attributes,
Expand All @@ -38,12 +38,15 @@ def extract_attributes_and_predicate(key, context = nil)
unless predicate || Ransack.options[:ignore_unknown_conditions]
raise ArgumentError, "No valid predicate for #{key}"
end
str = context.ransackable_alias(str) if context.present?
combinator = str.match(/_(or|and)_/) ? $1 : nil
if context.present? && context.attribute_method?(str)
attributes = [str]
else
attributes = str.split(/_and_|_or_/)
end
[attributes, predicate]

[attributes, predicate, combinator]
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/mongoid/adapters/mongoid/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ module Mongoid
end
end

describe '#ransack_alias' do
it 'translates an alias to the correct attributes' do
p = Person.create!(name: 'Meatloaf', email: '[email protected]')

s = Person.ransack(term_cont: 'atlo')
expect(s.result.to_a).to eq [p]

s = Person.ransack(term_cont: 'babi')
expect(s.result.to_a).to eq [p]

s = Person.ransack(term_cont: 'nomatch')
expect(s.result.to_a).to eq []
end
end

describe '#ransacker' do
# For infix tests
def self.sane_adapter?
Expand Down Expand Up @@ -213,6 +228,7 @@ def self.sane_adapter?
it { should include 'name' }
it { should include 'reversed_name' }
it { should include 'doubled_name' }
it { should include 'term' }
it { should include 'only_search' }
it { should_not include 'only_sort' }
it { should_not include 'only_admin' }
Expand All @@ -224,6 +240,7 @@ def self.sane_adapter?
it { should include 'name' }
it { should include 'reversed_name' }
it { should include 'doubled_name' }
it { should include 'term' }
it { should include 'only_search' }
it { should_not include 'only_sort' }
it { should include 'only_admin' }
Expand Down
15 changes: 15 additions & 0 deletions spec/mongoid/nodes/condition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ module Ransack
module Nodes
describe Condition do

context 'with an alias' do
subject {
Condition.extract(
Context.for(Person), 'term_start', Person.first(2).map(&:name)
)
}

specify { expect(subject.combinator).to eq 'or' }
specify { expect(subject.predicate.name).to eq 'start' }

it 'converts the alias to the correct attributes' do
expect(subject.attributes.map(&:name)).to eq(['name', 'email'])
end
end

context 'with multiple values and an _any predicate' do
subject { Condition.extract(Context.for(Person), 'name_eq_any', Person.first(2).map(&:name)) }

Expand Down
2 changes: 2 additions & 0 deletions spec/mongoid/support/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Person
has_many :articles
has_many :comments

ransack_alias :term, :name_or_email

# has_many :authored_article_comments, :through => :articles,
# :source => :comments, :foreign_key => :person_id

Expand Down
27 changes: 27 additions & 0 deletions spec/ransack/adapters/active_record/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,32 @@ module ActiveRecord
end
end

describe '#ransack_alias' do
it 'translates an alias to the correct attributes' do
p = Person.create!(name: 'Meatloaf', email: '[email protected]')

s = Person.ransack(term_cont: 'atlo')
expect(s.result.to_a).to eq [p]

s = Person.ransack(term_cont: 'babi')
expect(s.result.to_a).to eq [p]

s = Person.ransack(term_cont: 'nomatch')
expect(s.result.to_a).to eq []
end

it 'also works with associations' do
dad = Person.create!(name: 'Birdman')
son = Person.create!(name: 'Weezy', parent: dad)

s = Person.ransack(daddy_eq: 'Birdman')
expect(s.result.to_a).to eq [son]

s = Person.ransack(daddy_eq: 'Drake')
expect(s.result.to_a).to eq []
end
end

describe '#ransacker' do
# For infix tests
def self.sane_adapter?
Expand Down Expand Up @@ -416,6 +442,7 @@ def self.simple_escaping?
it { should include 'name' }
it { should include 'reversed_name' }
it { should include 'doubled_name' }
it { should include 'term' }
it { should include 'only_search' }
it { should_not include 'only_sort' }
it { should_not include 'only_admin' }
Expand Down
15 changes: 15 additions & 0 deletions spec/ransack/nodes/condition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ module Ransack
module Nodes
describe Condition do

context 'with an alias' do
subject {
Condition.extract(
Context.for(Person), 'term_start', Person.first(2).map(&:name)
)
}

specify { expect(subject.combinator).to eq 'or' }
specify { expect(subject.predicate.name).to eq 'start' }

it 'converts the alias to the correct attributes' do
expect(subject.attributes.map(&:name)).to eq(['name', 'email'])
end
end

context 'with multiple values and an _any predicate' do
subject {
Condition.extract(
Expand Down
3 changes: 3 additions & 0 deletions spec/support/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class Person < ActiveRecord::Base

alias_attribute :full_name, :name

ransack_alias :term, :name_or_email
ransack_alias :daddy, :parent_name

ransacker :reversed_name, formatter: proc { |v| v.reverse } do |parent|
parent.table[:name]
end
Expand Down

0 comments on commit 1de3453

Please sign in to comment.