Merge branch 'master' into bring-rails-3

Conflicts:
	.travis.yml
	Gemfile
	README.md
	lib/ransack/adapters/active_record/3.0/context.rb
	lib/ransack/adapters/active_record/3.1/context.rb
	lib/ransack/adapters/active_record/3.2/context.rb
	lib/ransack/adapters/active_record/base.rb
	lib/ransack/adapters/active_record/context.rb
	lib/ransack/constants.rb
	lib/ransack/context.rb
	lib/ransack/helpers/form_builder.rb
	lib/ransack/helpers/form_helper.rb
	lib/ransack/nodes/attribute.rb
	lib/ransack/nodes/condition.rb
	lib/ransack/nodes/grouping.rb
	lib/ransack/nodes/sort.rb
	lib/ransack/predicate.rb
	lib/ransack/translate.rb
	ransack.gemspec
	spec/blueprints/people.rb
	spec/ransack/adapters/active_record/base_spec.rb
	spec/ransack/adapters/active_record/context_spec.rb
	spec/ransack/configuration_spec.rb
	spec/ransack/dependencies_spec.rb
	spec/ransack/helpers/form_builder_spec.rb
	spec/ransack/helpers/form_helper_spec.rb
	spec/ransack/predicate_spec.rb
	spec/ransack/search_spec.rb
	spec/ransack/translate_spec.rb
	spec/support/schema.rb
This commit is contained in:
Washington Luiz 2014-04-10 00:28:29 -03:00
commit b4973315e9
35 changed files with 308 additions and 164 deletions

View File

@ -9,12 +9,21 @@ rvm:
- 2.1.1
env:
- RAILS=4-0-stable DB=sqlite3
- RAILS=4-0-stable DB=mysql
- RAILS=4-0-stable DB=postgres
- RAILS=4-1-stable DB=sqlite3
- RAILS=4-1-stable DB=mysql
- RAILS=4-1-stable DB=postgres
- RAILS=4-0-stable DB=sqlite3
- RAILS=4-0-stable DB=mysql
- RAILS=4-0-stable DB=postgres
- RAILS=3-2-stable DB=sqlite
- RAILS=3-2-stable DB=mysql
- RAILS=3-2-stable DB=postgres
- RAILS=3-1-stable DB=sqlite
- RAILS=3-1-stable DB=mysql
- RAILS=3-1-stable DB=postgres
- RAILS=3-0-stable DB=sqlite
- RAILS=3-0-stable DB=mysql
- RAILS=3-0-stable DB=postgres
before_script:
- mysql -e 'create database ransack collate utf8_general_ci;'

View File

@ -27,4 +27,7 @@ else
gem 'activerecord'
gem 'actionpack'
end
if rails == '3-0-stable'
gem 'mysql2', '< 0.3'
end
end

View File

@ -133,6 +133,15 @@ Once you've done so, you can make use of the helpers in Ransack::Helpers::FormBu
construct much more complex search forms, such as the one on the
[demo page](http://ransack-demo.heroku.com) (source code [here](https://github.com/activerecord-hackery/ransack_demo)).
### Ransack #search method
Ransack will try to to make `#search` available in your models, but in the case that `#search` has already been defined, you can use `#ransack` instead. For example the following would be equivalent:
```
Article.search(params[:q])
Article.ransack(params[:q])
```
### has_many and belongs_to associations
You can easily use Ransack to search in associated objects.

View File

@ -25,4 +25,4 @@ require 'ransack/adapters/active_record' if defined?(::ActiveRecord::Base)
require 'ransack/helpers'
require 'action_controller'
ActionController::Base.helper Ransack::Helpers::FormHelper
ActionController::Base.helper Ransack::Helpers::FormHelper

View File

@ -2,7 +2,7 @@
if Arel::Nodes::And < Arel::Nodes::Binary
class Ransack::Visitor
def visit_Ransack_Nodes_And(object)
nodes = object.values.map {|o| accept(o)}.compact
nodes = object.values.map { |o| accept(o) }.compact
return nil unless nodes.size > 0
if nodes.size > 1
@ -132,9 +132,15 @@ module Arel
end
def visit_Arel_Nodes_NamedFunction o
"#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
visit x
}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
"#{
o.name
}(#{
o.distinct ? 'DISTINCT ' : ''
}#{
o.expressions.map { |x| visit x }.join(', ')
})#{
o.alias ? " AS #{visit o.alias}" : ''
}"
end
def visit_Arel_Nodes_And o
@ -146,13 +152,17 @@ module Arel
end
def visit_Arel_Nodes_Values o
"VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
"VALUES (#{
o.expressions.zip(o.columns)
.map { |value, attr|
if Nodes::SqlLiteral === value
visit_Arel_Nodes_SqlLiteral value
else
quote(value, attr && column_for(attr))
end
}.join ', '})"
}
.join ', '
})"
end
end
end

View File

@ -11,6 +11,8 @@ module Ransack
JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency
JoinBase = JoinDependency::JoinBase
# Redefine a few things for ActiveRecord 3.0.
def initialize(object, options = {})
super
@arel_visitor = Arel::Visitors.visitor_for @engine
@ -24,10 +26,11 @@ module Ransack
viz = Visitor.new
relation = @object.where(viz.accept(search.base))
if search.sorts.any?
relation = relation.except(:order).reorder(viz.accept(search.sorts))
relation = relation.except(:order)
.reorder(viz.accept(search.sorts))
end
opts[:distinct] ? relation.select(
"DISTINCT #{@klass.quoted_table_name}.*") : relation
opts[:distinct] ?
relation.select("DISTINCT #{@klass.quoted_table_name}.*") : relation
end
def attribute_method?(str, klass = @klass)
@ -38,10 +41,15 @@ module Ransack
elsif (segments = str.split(/_/)).size > 1
remainder = []
found_assoc = nil
while !found_assoc && remainder.unshift(segments.pop) && segments.size > 0 do
assoc, poly_class = unpolymorphize_association(segments.join('_'))
while !found_assoc && remainder.unshift(segments.pop) &&
segments.size > 0 do
assoc, poly_class = unpolymorphize_association(
segments.join('_')
)
if found_assoc = get_association(assoc, klass)
exists = attribute_method?(remainder.join('_'), poly_class || found_assoc.klass)
exists = attribute_method?(
remainder.join('_'), poly_class || found_assoc.klass
)
end
end
end
@ -52,10 +60,12 @@ module Ransack
def table_for(parent)
parent.table
end
def type_for(attr)
return nil unless attr && attr.valid?
klassify(attr.parent).columns_hash[attr.arel_attribute.name.to_s].type
klassify(attr.parent)
.columns_hash[attr.arel_attribute.name.to_s]
.type
end
private
@ -68,22 +78,26 @@ module Ransack
elsif (segments = str.split(/_/)).size > 1
remainder = []
found_assoc = nil
while remainder.unshift(segments.pop) && segments.size > 0 && !found_assoc do
while remainder.unshift(segments.pop) && segments.size > 0 &&
!found_assoc do
assoc, klass = unpolymorphize_association(segments.join('_'))
if found_assoc = get_association(assoc, parent)
join = build_or_find_association(found_assoc.name, parent, klass)
parent, attr_name = get_parent_and_attribute_name(remainder.join('_'), join)
join = build_or_find_association(
found_assoc.name, parent, klass
)
parent, attr_name = get_parent_and_attribute_name(
remainder.join('_'), join
)
end
end
end
[parent, attr_name]
end
def get_association(str, parent = @base)
klass = klassify parent
ransackable_association?(str, klass) &&
klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
end
def join_dependency(relation)
@ -113,9 +127,9 @@ module Ransack
association_joins = buckets['association_join'] || []
stashed_association_joins = buckets['stashed_join'] || []
join_nodes = buckets['join_node'] || []
string_joins = (buckets['string_join'] || []).map { |x|
x.strip
}.uniq
string_joins = (buckets['string_join'] || [])
.map { |x| x.strip }
.uniq
join_list = relation.send :custom_join_sql, (string_joins + join_nodes)
@ -133,13 +147,16 @@ module Ransack
end
def build_or_find_association(name, parent = @base, klass = nil)
found_association = @join_dependency.join_associations.detect do |assoc|
found_association = @join_dependency.join_associations
.detect do |assoc|
assoc.reflection.name == name &&
assoc.parent == parent &&
(!klass || assoc.reflection.klass == klass)
end
unless found_association
@join_dependency.send(:build, Polyamorous::Join.new(name, @join_type, klass), parent)
@join_dependency.send(
:build, Polyamorous::Join.new(name, @join_type, klass), parent
)
found_association = @join_dependency.join_associations.last
# Leverage the stashed association functionality in AR
@object = @object.joins(found_association)

View File

@ -10,6 +10,8 @@ module Ransack
JoinDependency = ::ActiveRecord::Associations::JoinDependency
JoinPart = JoinDependency::JoinPart
# Redefine a few things for ActiveRecord 3.1.
def initialize(object, options = {})
super
@arel_visitor = Arel::Visitors.visitor_for @engine
@ -23,10 +25,12 @@ module Ransack
viz = Visitor.new
relation = @object.where(viz.accept(search.base))
if search.sorts.any?
relation = relation.except(:order).reorder(viz.accept(search.sorts))
relation = relation.except(:order)
.reorder(viz.accept(search.sorts))
end
opts[:distinct] ? relation.select(
"DISTINCT #{@klass.quoted_table_name}.*") : relation
opts[:distinct] ?
relation.select("DISTINCT #{@klass.quoted_table_name}.*") :
relation
end
def attribute_method?(str, klass = @klass)
@ -37,10 +41,15 @@ module Ransack
elsif (segments = str.split(/_/)).size > 1
remainder = []
found_assoc = nil
while !found_assoc && remainder.unshift(segments.pop) && segments.size > 0 do
assoc, poly_class = unpolymorphize_association(segments.join('_'))
while !found_assoc && remainder.unshift(segments.pop) &&
segments.size > 0 do
assoc, poly_class = unpolymorphize_association(
segments.join('_')
)
if found_assoc = get_association(assoc, klass)
exists = attribute_method?(remainder.join('_'), poly_class || found_assoc.klass)
exists = attribute_method?(
remainder.join('_'), poly_class || found_assoc.klass
)
end
end
end
@ -74,11 +83,16 @@ module Ransack
elsif (segments = str.split(/_/)).size > 1
remainder = []
found_assoc = nil
while remainder.unshift(segments.pop) && segments.size > 0 && !found_assoc do
while remainder.unshift(segments.pop) && segments.size > 0 &&
!found_assoc do
assoc, klass = unpolymorphize_association(segments.join('_'))
if found_assoc = get_association(assoc, parent)
join = build_or_find_association(found_assoc.name, parent, klass)
parent, attr_name = get_parent_and_attribute_name(remainder.join('_'), join)
join = build_or_find_association(
found_assoc.name, parent, klass
)
parent, attr_name = get_parent_and_attribute_name(
remainder.join('_'), join
)
end
end
end
@ -89,7 +103,7 @@ module Ransack
def get_association(str, parent = @base)
klass = klassify parent
ransackable_association?(str, klass) &&
klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
end
def join_dependency(relation)
@ -119,11 +133,12 @@ module Ransack
association_joins = buckets['association_join'] || []
stashed_association_joins = buckets['stashed_join'] || []
join_nodes = buckets['join_node'] || []
string_joins = (buckets['string_join'] || []).map { |x|
x.strip
}.uniq
string_joins = (buckets['string_join'] || [])
.map { |x| x.strip }
.uniq
join_list = relation.send :custom_join_ast, relation.table.from(relation.table), string_joins
join_list = relation.send :custom_join_ast,
relation.table.from(relation.table), string_joins
join_dependency = JoinDependency.new(
relation.klass,
@ -139,13 +154,16 @@ module Ransack
end
def build_or_find_association(name, parent = @base, klass = nil)
found_association = @join_dependency.join_associations.detect do |assoc|
found_association = @join_dependency.join_associations
.detect do |assoc|
assoc.reflection.name == name &&
assoc.parent == parent &&
(!klass || assoc.reflection.klass == klass)
end
unless found_association
@join_dependency.send(:build, Polyamorous::Join.new(name, @join_type, klass), parent)
@join_dependency.send(
:build, Polyamorous::Join.new(name, @join_type, klass), parent
)
found_association = @join_dependency.join_associations.last
# Leverage the stashed association functionality in AR
@object = @object.joins(found_association)

View File

@ -8,7 +8,7 @@ module Ransack
module ActiveRecord
class Context < ::Ransack::Context
# Redefine a few things that have changed with 3.2.
# Redefine a few things for ActiveRecord 3.2.
def initialize(object, options = {})
super

View File

@ -17,8 +17,8 @@ module Ransack
end
def ransacker(name, opts = {}, &block)
self._ransackers = _ransackers.merge name.to_s => Ransacker.new(
self, name, opts, &block)
self._ransackers = _ransackers.merge name.to_s => Ransacker
.new(self, name, opts, &block)
end
def ransackable_attributes(auth_object = nil)
@ -26,7 +26,8 @@ module Ransack
end
def ransortable_attributes(auth_object = nil)
# Here so users can overwrite the attributes that show up in the sort_select
# Here so users can overwrite the attributes
# that show up in the sort_select
ransackable_attributes(auth_object)
end

View File

@ -95,6 +95,5 @@ module Ransack
unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1')
end
end
end
end

View File

@ -61,7 +61,9 @@ module Ransack
obj
elsif obj.respond_to? :klass
obj.klass
elsif obj.respond_to? :base_klass
elsif obj.respond_to? :active_record # Rails 3
obj.active_record
elsif obj.respond_to? :base_klass # Rails 4
obj.base_klass
else
raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
@ -148,5 +150,9 @@ module Ransack
def sortable_attributes(str = '')
traverse(str).ransortable_attributes(auth_object)
end
def searchable_associations(str = '')
traverse(str).ransackable_associations(auth_object)
end
end
end

View File

@ -1,6 +1,4 @@
require 'action_view'
require 'simple_form' if
(ENV['RANSACK_FORM_BUILDER'] || '').match('SimpleForm')
require 'simple_form' if
(ENV['RANSACK_FORM_BUILDER'] || '').match('SimpleForm')
@ -109,7 +107,12 @@ module Ransack
def predicate_select(options = {}, html_options = {})
options[:compounds] = true if options[:compounds].nil?
default = options.delete(:default) || 'cont'
if ::ActiveRecord::VERSION::STRING >= "4"
default = options.delete(:default) || 'cont'
else
default = options.delete(:default) || 'eq'
end
keys = options[:compounds] ? Predicate.names :
Predicate.names.reject { |k| k.match(/_(any|all)$/) }
if only = options[:only]

View File

@ -23,7 +23,8 @@ module Ransack
end
class Name < String
attr_reader :singular, :plural, :element, :collection, :partial_path, :human, :param_key, :route_key, :i18n_key
attr_reader :singular, :plural, :element, :collection, :partial_path,
:human, :param_key, :route_key, :i18n_key
alias_method :cache_key, :collection
def initialize

View File

@ -52,4 +52,4 @@ module Ransack
end
end
end
end

View File

@ -19,7 +19,8 @@ module Ransack
m: combinator,
v: predicate.wants_array ? Array(values) : [values]
)
# TODO: Figure out what to do with multiple types of attributes, if anything.
# TODO: Figure out what to do with multiple types of attributes,
# if anything.
# Tempted to go with "garbage in, garbage out" on this one
predicate.validate(condition.values, condition.default_type) ?
condition : nil
@ -208,14 +209,14 @@ module Ransack
def inspect
data = [
['attributes', a.try(:map, &:name)],
['predicate', p],
['combinator', m],
['values', v.try(:map, &:value)]
]
.reject { |e| e[1].blank? }
.map { |v| "#{v[0]}: #{v[1]}" }
.join(', ')
['attributes', a.try(:map, &:name)],
['predicate', p],
['combinator', m],
['values', v.try(:map, &:value)]
]
.reject { |e| e[1].blank? }
.map { |v| "#{v[0]}: #{v[1]}" }
.join(', ')
"Condition <#{data}>"
end
@ -228,4 +229,4 @@ module Ransack
end
end
end
end

View File

@ -129,10 +129,9 @@ module Ransack
when /^(g|c|m|groupings|conditions|combinator)=?$/
true
else
name.
split(/_and_|_or_/).
select { |n| !@context.attribute_method?(n) }.
empty?
name.split(/_and_|_or_/)
.select { |n| !@context.attribute_method?(n) }
.empty?
end
end
@ -191,7 +190,6 @@ module Ransack
Predicate.detect_and_strip_from_string!(string)
string
end
end
end
end
end

View File

@ -31,4 +31,4 @@ module Ransack
end
end
end
end

View File

@ -41,4 +41,4 @@ module Ransack
end
end
end
end

View File

@ -107,4 +107,4 @@ module Ransack
end
end
end
end
end

View File

@ -29,8 +29,9 @@ module Ransack
end
def name_from_attribute_name(attribute_name)
names_by_decreasing_length.
detect { |p| attribute_name.to_s.match(/_#{p}$/) }
names_by_decreasing_length.detect {
|p| attribute_name.to_s.match(/_#{p}$/)
}
end
def for_attribute_name(attribute_name)
@ -75,4 +76,4 @@ module Ransack
end
end
end
end

View File

@ -21,4 +21,4 @@ module Ransack
end
end
end
end

View File

@ -104,7 +104,11 @@ module Ransack
end
def self.i18n_key(klass)
klass.model_name.i18n_key
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
klass.model_name.i18n_key.to_s.tr('.', '/')
else
klass.model_name.i18n_key.to_s
end
end
end
end

View File

@ -15,9 +15,9 @@ Gem::Specification.new do |s|
s.rubyforge_project = "ransack"
s.add_dependency 'actionpack', '>= 4.0'
s.add_dependency 'activerecord', '>= 4.0'
s.add_dependency 'activesupport', '>= 4.0'
s.add_dependency 'actionpack', '>= 3.0'
s.add_dependency 'activerecord', '>= 3.0'
s.add_dependency 'activesupport', '>= 3.0'
s.add_dependency 'i18n'
# s.add_dependency 'polyamorous', '~> 0.6.0'
s.add_development_dependency 'rspec', '~> 2.8.0'

View File

@ -5,4 +5,4 @@ Person.blueprint do
only_sort
only_search
only_admin
end
end

View File

@ -19,4 +19,3 @@ Sham.define do
end
Schema.create

View File

@ -37,6 +37,7 @@ module Ransack
# ransacker :doubled_name do |parent|
# Arel::Nodes::InfixOperation.new('||', parent.table[:name], parent.table[:name])
# end
it 'creates ransack attributes' do
s = Person.search(reversed_name_eq: 'htimS cirA')
s.result.should have(1).person
@ -60,18 +61,20 @@ module Ransack
s.result.count.should eq 1
end if defined?(Arel::Nodes::InfixOperation) && sane_adapter?
it "should remove empty key value pairs from the params hash" do
s = Person.search(children_reversed_name_eq: '')
s.result.to_sql.should_not match /LEFT OUTER JOIN/
end
if ::ActiveRecord::VERSION::STRING >= "4"
it "should remove empty key value pairs from the params hash" do
s = Person.search(children_reversed_name_eq: '')
s.result.to_sql.should_not match /LEFT OUTER JOIN/
end
it "should keep proper key value pairs in the params hash" do
s = Person.search(children_reversed_name_eq: 'Testing')
s.result.to_sql.should match /LEFT OUTER JOIN/
end
it "should keep proper key value pairs in the params hash" do
s = Person.search(children_reversed_name_eq: 'Testing')
s.result.to_sql.should match /LEFT OUTER JOIN/
end
it "should function correctly when nil is passed in" do
s = Person.search(nil)
it "should function correctly when nil is passed in" do
s = Person.search(nil)
end
end
it "should function correctly when using fields with dots in them" do
@ -219,4 +222,4 @@ module Ransack
end
end
end
end
end

View File

@ -48,4 +48,4 @@ module Ransack
end
end
end
end
end

View File

@ -65,4 +65,4 @@ module Ransack
Ransack.predicates.should_not have_key 'test_array_predicate_all'
end
end
end
end

View File

@ -1,6 +1,8 @@
#describe 'Ransack' do
# it 'can be required without errors' do
# output = `bundle exec ruby -e "require 'ransack'" 2>&1`
# output.should be_empty
# end
#end
unless ::ActiveRecord::VERSION::STRING >= "4"
describe 'Ransack' do
it 'can be required without errors' do
output = `bundle exec ruby -e "require 'ransack'" 2>&1`
output.should be_empty
end
end
end

View File

@ -55,7 +55,11 @@ module Ransack
describe '#sort_link' do
it 'sort_link for ransack attribute' do
sort_link = @f.sort_link :name, controller: 'people'
sort_link.should match /people\?q(%5B|\[)s(%5D|\])=name\+asc/
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
sort_link.should match /people\?q%5Bs%5D=name\+asc/
else
sort_link.should match /people\?q(%5B|\[)s(%5D|\])=name\+asc/
end
sort_link.should match /sort_link/
sort_link.should match /Full Name<\/a>/
end

View File

@ -33,48 +33,63 @@ module Ransack
controller: 'people'
)
}
it { should match /people\?q(%5B|\[)s(%5D|\])=name\+asc/ }
it { should match(
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
/people\?q%5Bs%5D=name\+asc/
else
/people\?q(%5B|\[)s(%5D|\])=name\+asc/
end)
}
it { should match /sort_link desc/ }
it { should match /Full Name &#9660;/ }
end
describe '#sort_link with default search_key defined as symbol' do
subject { @controller.view_context.
sort_link(
Person.search({ sorts: ['name desc'] }, search_key: :people_search),
:name,
controller: 'people'
subject { @controller.
view_context.sort_link(
Person.search({ :sorts => ['name desc'] }, :search_key => :people_search),
:name, :controller => 'people'
)
}
it { should match /people\?people_search(%5B|\[)s(%5D|\])=name\+asc/ }
it { should match(
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
/people\?people_search%5Bs%5D=name\+asc/
else
/people\?people_search(%5B|\[)s(%5D|\])=name\+asc/
end)
}
end
describe '#sort_link with default search_key defined as string' do
subject { @controller.view_context.
sort_link(
Person.search({ sorts: ['name desc'] }, search_key: 'people_search'),
:name,
controller: 'people'
subject {
@controller.view_context.sort_link(
Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'),
:name, :controller => 'people'
)
}
it { should match /people\?people_search(%5B|\[)s(%5D|\])=name\+asc/ }
it { should match(
if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./
/people\?people_search%5Bs%5D=name\+asc/
else
/people\?people_search(%5B|\[)s(%5D|\])=name\+asc/
end)
}
end
context 'view has existing parameters' do
before do
@controller.view_context.
params.merge!({ exist: 'existing' })
@controller.view_context.params.merge!({ :exist => 'existing' })
end
describe '#sort_link should not remove existing params' do
subject {
@controller.view_context.
sort_link(
Person.search({ sorts: ['name desc'] }, search_key: 'people_search'),
:name,
controller: 'people'
)
@controller.view_context.sort_link(
Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'),
:name, :controller => 'people'
)
}
it {
should match /exist\=existing/
}
it { should match /exist\=existing/ }
end
end
end

View File

@ -42,17 +42,15 @@ module Ransack
end
describe 'cont' do
it_has_behavior 'wildcard escaping', :name_cont,
(
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
/"people"."name" ILIKE '%\\%\\._\\\\%'/
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
/`people`.`name` LIKE '%\\\\%\\\\._\\\\\\\\%'/
else
/"people"."name" LIKE '%%._\\%'/
end
) do
/"people"."name" LIKE '%%._\\%'/
end) do
subject { @s }
end
@ -65,15 +63,13 @@ module Ransack
describe 'not_cont' do
it_has_behavior 'wildcard escaping', :name_not_cont,
(
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
/"people"."name" NOT ILIKE '%\\%\\._\\\\%'/
elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
/`people`.`name` NOT LIKE '%\\\\%\\\\._\\\\\\\\%'/
else
/"people"."name" NOT LIKE '%%._\\%'/
end
) do
/"people"."name" NOT LIKE '%%._\\%'/
end) do
subject { @s }
end

View File

@ -89,13 +89,11 @@ module Ransack
it 'accepts "attributes" hashes for conditions' do
search = Search.new(Person,
c: {
'0' => { a: ['name'], p: 'eq', v: ['Ernie'] },
'1' => {
a: ['children_name', 'parent_name'],
p: 'eq', v: ['Ernie'], m: 'or'
}
}
:c => {
'0' => { :a => ['name'], :p => 'eq', :v => ['Ernie'] },
'1' => { :a => ['children_name', 'parent_name'],
:p => 'eq', :v => ['Ernie'], :m => 'or' }
}
)
conditions = search.base.conditions
conditions.should have(2).items
@ -105,8 +103,7 @@ module Ransack
it 'creates conditions for custom predicates that take arrays' do
Ransack.configure do |config|
config.add_predicate 'ary_pred',
wants_array: true
config.add_predicate 'ary_pred', :wants_array => true
end
search = Search.new(Person, name_ary_pred: ['Ernie', 'Bert'])
@ -183,18 +180,42 @@ module Ransack
second.should match /#{children_people_name_field} = 'Bert'/
end
it 'returns distinct records when passed distinct: true' do
search = Search.new(
Person, g: [
{ m: 'or',
comments_body_cont: 'e',
articles_comments_body_cont: 'e'
}
]
)
search.result.load.should have(9000).items
search.result(distinct: true).should have(10).items
search.result.load.uniq.should eq search.result(distinct: true).load
if ::ActiveRecord::VERSION::STRING >= "4"
it 'returns distinct records when passed distinct: true' do
search = Search.new(
Person, g: [
{ m: 'or',
comments_body_cont: 'e',
articles_comments_body_cont: 'e'
}
]
)
search.result.load.should have(9000).items
search.result(distinct: true).should have(10).items
search.result.load.uniq.should eq search.result(distinct: true).load
end
else
it 'returns distinct records when passed :distinct => true' do
search = Search.new(
Person, :g => [
{ :m => 'or',
:comments_body_cont => 'e',
:articles_comments_body_cont => 'e'
}
]
)
if ActiveRecord::VERSION::MAJOR == 3
all_or_load, uniq_or_distinct = :all, :uniq
else
all_or_load, uniq_or_distinct = :load, :distinct
end
search.result.send(all_or_load).
should have(920).items
search.result(:distinct => true).
should have(330).items
search.result.send(all_or_load).send(uniq_or_distinct).
should eq search.result(:distinct => true).send(all_or_load)
end
end
end

View File

@ -6,9 +6,7 @@ module Ransack
describe '.attribute' do
it 'translate namespaced attribute like AR does' do
ar_translation = ::Namespace::Article.human_attribute_name(:title)
ransack_translation = Ransack::Translate.attribute(
:title, :context => ::Namespace::Article.search.context
)
ransack_translation = Ransack::Translate.attribute(:title, :context => ::Namespace::Article.search.context)
ransack_translation.should eq ar_translation
end
end

View File

@ -23,7 +23,11 @@ else
end
class Person < ActiveRecord::Base
default_scope { order(id: :desc) }
if ActiveRecord::VERSION::MAJOR == 3
default_scope order('id DESC')
else
default_scope { order(id: :desc) }
end
belongs_to :parent, class_name: 'Person', foreign_key: :parent_id
has_many :children, class_name: 'Person', foreign_key: :parent_id
has_many :articles
@ -57,6 +61,22 @@ class Person < ActiveRecord::Base
column_names + _ransackers.keys - ['only_search', 'only_admin']
end
end
def self.ransackable_attributes(auth_object = nil)
if auth_object == :admin
column_names + _ransackers.keys - ['only_sort']
else
column_names + _ransackers.keys - ['only_sort', 'only_admin']
end
end
def self.ransortable_attributes(auth_object = nil)
if auth_object == :admin
column_names + _ransackers.keys - ['only_search']
else
column_names + _ransackers.keys - ['only_search', 'only_admin']
end
end
end
class Article < ActiveRecord::Base
@ -72,6 +92,12 @@ module Namespace
end
end
module Namespace
class Article < ::Article
end
end
class Comment < ActiveRecord::Base
belongs_to :article
belongs_to :person
@ -128,6 +154,7 @@ module Schema
t.string :notable_type
t.string :note
end
end
10.times do
@ -148,6 +175,5 @@ module Schema
Comment.make(
body: 'First post!', article: Article.make(title: 'Hello, world!')
)
end
end
end