ransack 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +47 -3
  3. data/CHANGELOG.md +106 -18
  4. data/CONTRIBUTING.md +56 -23
  5. data/Gemfile +16 -5
  6. data/README.md +114 -38
  7. data/Rakefile +30 -2
  8. data/lib/ransack.rb +9 -0
  9. data/lib/ransack/adapters/active_record/3.0/compat.rb +11 -8
  10. data/lib/ransack/adapters/active_record/3.0/context.rb +14 -22
  11. data/lib/ransack/adapters/active_record/3.1/context.rb +14 -22
  12. data/lib/ransack/adapters/active_record/context.rb +36 -31
  13. data/lib/ransack/adapters/active_record/ransack/constants.rb +113 -0
  14. data/lib/ransack/adapters/active_record/ransack/context.rb +64 -0
  15. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +48 -0
  16. data/lib/ransack/adapters/active_record/ransack/translate.rb +12 -0
  17. data/lib/ransack/adapters/active_record/ransack/visitor.rb +24 -0
  18. data/lib/ransack/adapters/mongoid.rb +13 -0
  19. data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
  20. data/lib/ransack/adapters/mongoid/attributes/attribute.rb +37 -0
  21. data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +17 -0
  22. data/lib/ransack/adapters/mongoid/attributes/predications.rb +141 -0
  23. data/lib/ransack/adapters/mongoid/base.rb +126 -0
  24. data/lib/ransack/adapters/mongoid/context.rb +208 -0
  25. data/lib/ransack/adapters/mongoid/inquiry_hash.rb +23 -0
  26. data/lib/ransack/adapters/mongoid/ransack/constants.rb +88 -0
  27. data/lib/ransack/adapters/mongoid/ransack/context.rb +60 -0
  28. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +27 -0
  29. data/lib/ransack/adapters/mongoid/ransack/translate.rb +13 -0
  30. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +24 -0
  31. data/lib/ransack/adapters/mongoid/table.rb +35 -0
  32. data/lib/ransack/configuration.rb +22 -4
  33. data/lib/ransack/constants.rb +26 -120
  34. data/lib/ransack/context.rb +32 -60
  35. data/lib/ransack/helpers/form_builder.rb +50 -36
  36. data/lib/ransack/helpers/form_helper.rb +148 -104
  37. data/lib/ransack/naming.rb +11 -11
  38. data/lib/ransack/nodes.rb +2 -0
  39. data/lib/ransack/nodes/bindable.rb +12 -4
  40. data/lib/ransack/nodes/condition.rb +5 -22
  41. data/lib/ransack/nodes/grouping.rb +9 -10
  42. data/lib/ransack/nodes/sort.rb +3 -2
  43. data/lib/ransack/nodes/value.rb +1 -2
  44. data/lib/ransack/predicate.rb +3 -3
  45. data/lib/ransack/search.rb +46 -13
  46. data/lib/ransack/translate.rb +8 -8
  47. data/lib/ransack/version.rb +1 -1
  48. data/lib/ransack/visitor.rb +4 -16
  49. data/ransack.gemspec +1 -0
  50. data/spec/mongoid/adapters/mongoid/base_spec.rb +276 -0
  51. data/spec/mongoid/adapters/mongoid/context_spec.rb +56 -0
  52. data/spec/mongoid/configuration_spec.rb +66 -0
  53. data/spec/mongoid/dependencies_spec.rb +8 -0
  54. data/spec/mongoid/helpers/ransack_helper.rb +11 -0
  55. data/spec/mongoid/nodes/condition_spec.rb +34 -0
  56. data/spec/mongoid/nodes/grouping_spec.rb +13 -0
  57. data/spec/mongoid/predicate_spec.rb +155 -0
  58. data/spec/mongoid/search_spec.rb +446 -0
  59. data/spec/mongoid/support/mongoid.yml +6 -0
  60. data/spec/mongoid/support/schema.rb +128 -0
  61. data/spec/mongoid/translate_spec.rb +14 -0
  62. data/spec/mongoid_spec_helper.rb +59 -0
  63. data/spec/ransack/adapters/active_record/base_spec.rb +68 -35
  64. data/spec/ransack/dependencies_spec.rb +3 -1
  65. data/spec/ransack/helpers/form_builder_spec.rb +6 -6
  66. data/spec/ransack/helpers/form_helper_spec.rb +114 -47
  67. data/spec/ransack/nodes/condition_spec.rb +2 -2
  68. data/spec/ransack/search_spec.rb +2 -6
  69. data/spec/ransack/translate_spec.rb +1 -1
  70. data/spec/spec_helper.rb +2 -3
  71. data/spec/support/schema.rb +9 -0
  72. metadata +49 -4
@@ -8,6 +8,7 @@ module Ransack
8
8
 
9
9
  class << self
10
10
  def extract(context, str)
11
+ return unless str
11
12
  attr, direction = str.split(/\s+/,2)
12
13
  self.new(context).build(name: attr, dir: direction)
13
14
  end
@@ -37,10 +38,10 @@ module Ransack
37
38
  def dir=(dir)
38
39
  dir = dir.downcase if dir
39
40
  @dir =
40
- if Ransack::Constants::ASC_DESC.include?(dir)
41
+ if Constants::ASC_DESC.include?(dir)
41
42
  dir
42
43
  else
43
- Ransack::Constants::ASC
44
+ Constants::ASC
44
45
  end
45
46
  end
46
47
 
@@ -14,8 +14,7 @@ module Ransack
14
14
  end
15
15
 
16
16
  def eql?(other)
17
- self.class == other.class &&
18
- self.value == other.value
17
+ self.class == other.class && self.value == other.value
19
18
  end
20
19
  alias :== :eql?
21
20
 
@@ -19,7 +19,7 @@ module Ransack
19
19
 
20
20
  def detect_and_strip_from_string!(str)
21
21
  if p = detect_from_string(str)
22
- str.sub! /_#{p}$/, Ransack::Constants::EMPTY
22
+ str.sub! /_#{p}$/, Constants::EMPTY
23
23
  p
24
24
  end
25
25
  end
@@ -49,7 +49,7 @@ module Ransack
49
49
  lambda { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
50
50
  @compound = opts[:compound]
51
51
  @wants_array = opts[:wants_array] == true || @compound ||
52
- Ransack::Constants::IN_NOT_IN.include?(@arel_predicate)
52
+ Constants::IN_NOT_IN.include?(@arel_predicate)
53
53
  end
54
54
 
55
55
  def eql?(other)
@@ -71,7 +71,7 @@ module Ransack
71
71
  end
72
72
 
73
73
  def validate(vals, type = @type)
74
- vals.select { |v| validator.call(type ? v.cast(type) : v.value) }.any?
74
+ vals.any? { |v| validator.call(type ? v.cast(type) : v.value) }
75
75
  end
76
76
 
77
77
  end
@@ -1,5 +1,14 @@
1
1
  require 'ransack/nodes'
2
2
  require 'ransack/context'
3
+
4
+ if defined?(::ActiveRecord::Base)
5
+ require 'ransack/adapters/active_record/ransack/context'
6
+ end
7
+
8
+ if defined?(::Mongoid)
9
+ require 'ransack/adapters/mongoid/ransack/context'
10
+ end
11
+
3
12
  require 'ransack/naming'
4
13
 
5
14
  module Ransack
@@ -23,10 +32,10 @@ module Ransack
23
32
  @context = options[:context] || Context.for(object, options)
24
33
  @context.auth_object = options[:auth_object]
25
34
  @base = Nodes::Grouping.new(
26
- @context,
27
- options[:grouping] || Ransack::Constants::AND
35
+ @context, options[:grouping] || Constants::AND
28
36
  )
29
37
  @scope_args = {}
38
+ @sorts ||= []
30
39
  build(params.with_indifferent_access)
31
40
  end
32
41
 
@@ -36,7 +45,7 @@ module Ransack
36
45
 
37
46
  def build(params)
38
47
  collapse_multiparameter_attributes!(params).each do |key, value|
39
- if Ransack::Constants::S_SORTS.include?(key)
48
+ if Constants::S_SORTS.include?(key)
40
49
  send("#{key}=", value)
41
50
  elsif base.attribute_method?(key)
42
51
  base.send("#{key}=", value)
@@ -75,7 +84,7 @@ module Ransack
75
84
  alias :s= :sorts=
76
85
 
77
86
  def sorts
78
- @sorts ||= []
87
+ @sorts
79
88
  end
80
89
  alias :s :sorts
81
90
 
@@ -91,7 +100,7 @@ module Ransack
91
100
 
92
101
  def method_missing(method_id, *args)
93
102
  method_name = method_id.to_s
94
- getter_name = method_name.sub(/=$/, Ransack::Constants::EMPTY)
103
+ getter_name = method_name.sub(/=$/, Constants::EMPTY)
95
104
  if base.attribute_method?(getter_name)
96
105
  base.send(method_id, *args)
97
106
  elsif @context.ransackable_scope?(getter_name, @context.object)
@@ -111,8 +120,9 @@ module Ransack
111
120
  ([:scope, @scope_args] if @scope_args.present?),
112
121
  [:base, base.inspect]
113
122
  ]
114
- .compact.map { |d| d.join(': '.freeze) }
115
- .join(Ransack::Constants::COMMA_SPACE)
123
+ .compact
124
+ .map { |d| d.join(Constants::COLON_SPACE) }
125
+ .join(Constants::COMMA_SPACE)
116
126
 
117
127
  "Ransack::Search<#{details}>"
118
128
  end
@@ -123,22 +133,45 @@ module Ransack
123
133
  if @context.scope_arity(key) == 1
124
134
  @scope_args[key] = args.is_a?(Array) ? args[0] : args
125
135
  else
126
- @scope_args[key] = args
136
+ @scope_args[key] = args.is_a?(Array) ? sanitized_scope_args(args) : args
137
+ end
138
+ @context.chain_scope(key, sanitized_scope_args(args))
139
+ end
140
+
141
+ def sanitized_scope_args(args)
142
+ if args.is_a?(Array)
143
+ args = args.map(&method(:sanitized_scope_args))
144
+ end
145
+
146
+ if Constants::TRUE_VALUES.include? args
147
+ true
148
+ elsif Constants::FALSE_VALUES.include? args
149
+ false
150
+ else
151
+ args
127
152
  end
128
- @context.chain_scope(key, args)
129
153
  end
130
154
 
131
155
  def collapse_multiparameter_attributes!(attrs)
132
- attrs.keys.each do |k|
133
- if k.include?('('.freeze)
156
+ attrs.each_key do |k|
157
+ if k.include?(Constants::LEFT_PARENTHESIS)
134
158
  real_attribute, position = k.split(/\(|\)/)
135
- cast = %w(a s i).freeze.include?(position.last) ? position.last : nil
159
+ cast =
160
+ if Constants::A_S_I.include?(position.last)
161
+ position.last
162
+ else
163
+ nil
164
+ end
136
165
  position = position.to_i - 1
137
166
  value = attrs.delete(k)
138
167
  attrs[real_attribute] ||= []
139
168
  attrs[real_attribute][position] =
140
169
  if cast
141
- value.blank? && cast == 'i'.freeze ? nil : value.send("to_#{cast}")
170
+ if value.blank? && cast == Constants::I
171
+ nil
172
+ else
173
+ value.send("to_#{cast}")
174
+ end
142
175
  else
143
176
  value
144
177
  end
@@ -25,8 +25,7 @@ module Ransack
25
25
  |x| x.respond_to?(:model_name)
26
26
  }
27
27
  predicate = Predicate.detect_from_string(original_name)
28
- attributes_str = original_name
29
- .sub(/_#{predicate}$/, Ransack::Constants::EMPTY)
28
+ attributes_str = original_name.sub(/_#{predicate}$/, Constants::EMPTY)
30
29
  attribute_names = attributes_str.split(/_and_|_or_/)
31
30
  combinator = attributes_str.match(/_and_/) ? :and : :or
32
31
  defaults = base_ancestors.map do |klass|
@@ -74,7 +73,7 @@ module Ransack
74
73
  def self.attribute_name(context, name, include_associations = nil)
75
74
  @context, @name = context, name
76
75
  @assoc_path = context.association_path(name)
77
- @attr_name = @name.sub(/^#{@assoc_path}_/, Ransack::Constants::EMPTY)
76
+ @attr_name = @name.sub(/^#{@assoc_path}_/, Constants::EMPTY)
78
77
  associated_class = @context.traverse(@assoc_path) if @assoc_path.present?
79
78
  @include_associated = include_associations && associated_class
80
79
 
@@ -150,11 +149,12 @@ module Ransack
150
149
  end
151
150
 
152
151
  def self.i18n_key(klass)
153
- if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
154
- klass.model_name.i18n_key.to_s.tr('.'.freeze, '/'.freeze)
155
- else
156
- klass.model_name.i18n_key.to_s
157
- end
152
+ # if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
153
+ # klass.model_name.i18n_key.to_s.tr('.', '/')
154
+ # else
155
+ # klass.model_name.i18n_key.to_s
156
+ # end
157
+ raise "not implemented"
158
158
  end
159
159
  end
160
160
  end
@@ -1,3 +1,3 @@
1
1
  module Ransack
2
- VERSION = "1.5.1"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -18,7 +18,7 @@ module Ransack
18
18
  end
19
19
 
20
20
  def visit_Ransack_Nodes_Grouping(object)
21
- if object.combinator == Ransack::Constants::OR
21
+ if object.combinator == Constants::OR
22
22
  visit_or(object)
23
23
  else
24
24
  visit_and(object)
@@ -26,14 +26,7 @@ module Ransack
26
26
  end
27
27
 
28
28
  def visit_and(object)
29
- nodes = object.values.map { |o| accept(o) }.compact
30
- return nil unless nodes.size > 0
31
-
32
- if nodes.size > 1
33
- Arel::Nodes::Grouping.new(Arel::Nodes::And.new(nodes))
34
- else
35
- nodes.first
36
- end
29
+ raise "not implemented"
37
30
  end
38
31
 
39
32
  def visit_or(object)
@@ -52,12 +45,7 @@ module Ransack
52
45
  end
53
46
 
54
47
  def quoted?(object)
55
- case object
56
- when Arel::Nodes::SqlLiteral, Bignum, Fixnum
57
- false
58
- else
59
- true
60
- end
48
+ raise "not implemented"
61
49
  end
62
50
 
63
51
  def visit(object)
@@ -66,7 +54,7 @@ module Ransack
66
54
 
67
55
  DISPATCH = Hash.new do |hash, klass|
68
56
  hash[klass] = "visit_#{
69
- klass.name.gsub('::'.freeze, Ransack::Constants::UNDERSCORE)
57
+ klass.name.gsub(Constants::TWO_COLONS, Constants::UNDERSCORE)
70
58
  }"
71
59
  end
72
60
 
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "https://github.com/activerecord-hackery/ransack"
12
12
  s.summary = %q{Object-based searching for ActiveRecord (currently).}
13
13
  s.description = %q{Ransack is the successor to the MetaSearch gem. It improves and expands upon MetaSearch's functionality, but does not have a 100%-compatible API.}
14
+ s.required_ruby_version = '>= 1.9'
14
15
  s.license = 'MIT'
15
16
 
16
17
  s.rubyforge_project = "ransack"
@@ -0,0 +1,276 @@
1
+ require 'mongoid_spec_helper'
2
+
3
+ module Ransack
4
+ module Adapters
5
+ module Mongoid
6
+ describe Base do
7
+
8
+ subject { Person }
9
+
10
+ it { should respond_to :ransack }
11
+ it { should respond_to :search }
12
+
13
+ describe '#search' do
14
+ subject { Person.search }
15
+
16
+ it { should be_a Search }
17
+ it 'has a Mongoid::Criteria as its object' do
18
+ expect(subject.object).to be_an ::Mongoid::Criteria
19
+ end
20
+
21
+ context 'with scopes' do
22
+ before do
23
+ Person.stub :ransackable_scopes => [:active, :over_age]
24
+ end
25
+
26
+ it "applies true scopes" do
27
+ search = Person.search('active' => true)
28
+ expect(search.result.selector).to eq({ 'active' => 1 })
29
+ end
30
+
31
+ it "ignores unlisted scopes" do
32
+ search = Person.search('restricted' => true)
33
+ expect(search.result.selector).to_not eq({ 'restricted' => 1})
34
+ end
35
+
36
+ it "ignores false scopes" do
37
+ search = Person.search('active' => false)
38
+ expect(search.result.selector).to_not eq({ 'active' => 1 })
39
+ end
40
+
41
+ it "passes values to scopes" do
42
+ search = Person.search('over_age' => 18)
43
+ expect(search.result.selector).to eq({ 'age' => { '$gt' => 18 } })
44
+ end
45
+
46
+ it "chains scopes" do
47
+ search = Person.search('over_age' => 18, 'active' => true)
48
+ expect(search.result.selector).to eq({ 'age' => { '$gt' => 18 }, 'active' => 1 })
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#ransacker' do
54
+ # For infix tests
55
+ def self.sane_adapter?
56
+ case ::Mongoid::Document.connection.adapter_name
57
+ when "SQLite3", "PostgreSQL"
58
+ true
59
+ else
60
+ false
61
+ end
62
+ end
63
+ # # in schema.rb, class Person:
64
+ # ransacker :reversed_name, formatter: proc { |v| v.reverse } do |parent|
65
+ # parent.table[:name]
66
+ # end
67
+
68
+ # ransacker :doubled_name do |parent|
69
+ # Arel::Nodes::InfixOperation.new(
70
+ # '||', parent.table[:name], parent.table[:name]
71
+ # )
72
+ # end
73
+
74
+ it 'creates ransack attributes' do
75
+ s = Person.search(:reversed_name_eq => 'htimS cirA')
76
+ expect(s.result.size).to eq(Person.where(name: 'Aric Smith').count)
77
+
78
+ expect(s.result.first).to eq Person.where(name: 'Aric Smith').first
79
+ end
80
+
81
+ context 'with joins' do
82
+ before { pending 'not implemented for mongoid' }
83
+
84
+ it 'can be accessed through associations' do
85
+ s = Person.search(:children_reversed_name_eq => 'htimS cirA')
86
+ expect(s.result.to_sql).to match(
87
+ /#{quote_table_name("children_people")}.#{
88
+ quote_column_name("name")} = 'Aric Smith'/
89
+ )
90
+ end
91
+
92
+ it "should keep proper key value pairs in the params hash" do
93
+ s = Person.search(:children_reversed_name_eq => 'Testing')
94
+ expect(s.result.to_sql).to match /LEFT OUTER JOIN/
95
+ end
96
+
97
+ end
98
+
99
+ it 'allows an "attribute" to be an InfixOperation' do
100
+ s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith')
101
+ expect(s.result.first).to eq Person.where(name: 'Aric Smith').first
102
+ end if defined?(Arel::Nodes::InfixOperation) && sane_adapter?
103
+
104
+ it "doesn't break #count if using InfixOperations" do
105
+ s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith')
106
+ expect(s.result.count).to eq 1
107
+ end if defined?(Arel::Nodes::InfixOperation) && sane_adapter?
108
+
109
+ it "should remove empty key value pairs from the params hash" do
110
+ s = Person.search(:reversed_name_eq => '')
111
+ expect(s.result.selector).to eq({})
112
+ end
113
+
114
+ it "should function correctly when nil is passed in" do
115
+ s = Person.search(nil)
116
+ end
117
+
118
+ it "should function correctly when a blank string is passed in" do
119
+ s = Person.search('')
120
+ end
121
+
122
+ it "should function correctly when using fields with dots in them" do
123
+ s = Person.search(:email_cont => "example.com")
124
+ expect(s.result.exists?).to be true
125
+
126
+ s = Person.search(:email_cont => "example.co.")
127
+ expect(s.result.exists?).not_to be true
128
+ end
129
+
130
+ it "should function correctly when using fields with % in them" do
131
+ Person.create!(:name => "110%-er")
132
+ s = Person.search(:name_cont => "10%")
133
+ expect(s.result.exists?).to be true
134
+ end
135
+
136
+ it "should function correctly when using fields with backslashes in them" do
137
+ Person.create!(:name => "\\WINNER\\")
138
+ s = Person.search(:name_cont => "\\WINNER\\")
139
+ expect(s.result.exists?).to be true
140
+ end
141
+
142
+ it 'allows sort by "only_sort" field' do
143
+ pending "it doesn't work :("
144
+ s = Person.search(
145
+ "s" => { "0" => { "dir" => "desc", "name" => "only_sort" } }
146
+ )
147
+ expect(s.result.to_sql).to match(
148
+ /ORDER BY #{quote_table_name("people")}.#{
149
+ quote_column_name("only_sort")} ASC/
150
+ )
151
+ end
152
+
153
+ it "doesn't sort by 'only_search' field" do
154
+ pending "it doesn't work :("
155
+ s = Person.search(
156
+ "s" => { "0" => { "dir" => "asc", "name" => "only_search" } }
157
+ )
158
+ expect(s.result.to_sql).not_to match(
159
+ /ORDER BY #{quote_table_name("people")}.#{
160
+ quote_column_name("only_search")} ASC/
161
+ )
162
+ end
163
+
164
+ it 'allows search by "only_search" field' do
165
+ s = Person.search(:only_search_eq => 'htimS cirA')
166
+ expect(s.result.selector).to eq({'only_search' => 'htimS cirA'})
167
+ end
168
+
169
+ it "can't be searched by 'only_sort'" do
170
+ s = Person.search(:only_sort_eq => 'htimS cirA')
171
+ expect(s.result.selector).not_to eq({'only_sort' => 'htimS cirA'})
172
+ end
173
+
174
+ it 'allows sort by "only_admin" field, if auth_object: :admin' do
175
+ s = Person.search(
176
+ { "s" => { "0" => { "dir" => "asc", "name" => "only_admin" } } },
177
+ { auth_object: :admin }
178
+ )
179
+ expect(s.result.options).to eq({ sort: { '_id' => -1, 'only_admin' => 1 } })
180
+ end
181
+
182
+ it "doesn't sort by 'only_admin' field, if auth_object: nil" do
183
+ s = Person.search(
184
+ "s" => { "0" => { "dir" => "asc", "name" => "only_admin" } }
185
+ )
186
+ expect(s.result.options).to eq({ sort: {'_id' => -1}})
187
+ end
188
+
189
+ it 'allows search by "only_admin" field, if auth_object: :admin' do
190
+ s = Person.search(
191
+ { :only_admin_eq => 'htimS cirA' },
192
+ { :auth_object => :admin }
193
+ )
194
+ expect(s.result.selector).to eq({ 'only_admin' => 'htimS cirA' })
195
+ end
196
+
197
+ it "can't be searched by 'only_admin', if auth_object: nil" do
198
+ s = Person.search(:only_admin_eq => 'htimS cirA')
199
+ expect(s.result.selector).to eq({})
200
+ end
201
+
202
+ it 'searches by id' do
203
+ ids = ['some_bson_id', 'another_bson_id']
204
+ s = Person.search(:id_in => ids)
205
+ expect(s.result.selector).to eq({ '_id' => { '$in' => ids } })
206
+ end
207
+ end
208
+
209
+ describe '#ransackable_attributes' do
210
+ context 'when auth_object is nil' do
211
+ subject { Person.ransackable_attributes }
212
+
213
+ it { should include 'name' }
214
+ it { should include 'reversed_name' }
215
+ it { should include 'doubled_name' }
216
+ it { should include 'only_search' }
217
+ it { should_not include 'only_sort' }
218
+ it { should_not include 'only_admin' }
219
+ end
220
+
221
+ context 'with auth_object :admin' do
222
+ subject { Person.ransackable_attributes(:admin) }
223
+
224
+ it { should include 'name' }
225
+ it { should include 'reversed_name' }
226
+ it { should include 'doubled_name' }
227
+ it { should include 'only_search' }
228
+ it { should_not include 'only_sort' }
229
+ it { should include 'only_admin' }
230
+ end
231
+ end
232
+
233
+ describe '#ransortable_attributes' do
234
+ context 'when auth_object is nil' do
235
+ subject { Person.ransortable_attributes }
236
+
237
+ it { should include 'name' }
238
+ it { should include 'reversed_name' }
239
+ it { should include 'doubled_name' }
240
+ it { should include 'only_sort' }
241
+ it { should_not include 'only_search' }
242
+ it { should_not include 'only_admin' }
243
+ end
244
+
245
+ context 'with auth_object :admin' do
246
+ subject { Person.ransortable_attributes(:admin) }
247
+
248
+ it { should include 'name' }
249
+ it { should include 'reversed_name' }
250
+ it { should include 'doubled_name' }
251
+ it { should include 'only_sort' }
252
+ it { should_not include 'only_search' }
253
+ it { should include 'only_admin' }
254
+ end
255
+ end
256
+
257
+ describe '#ransackable_associations' do
258
+ before { pending "not implemented for mongoid" }
259
+
260
+ subject { Person.ransackable_associations }
261
+
262
+ it { should include 'parent' }
263
+ it { should include 'children' }
264
+ it { should include 'articles' }
265
+ end
266
+
267
+ describe '#ransackable_scopes' do
268
+ subject { Person.ransackable_scopes }
269
+
270
+ it { should eq [] }
271
+ end
272
+
273
+ end
274
+ end
275
+ end
276
+ end