ransack 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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