ransack 0.2.1 → 0.3.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.
data/Gemfile CHANGED
@@ -1,11 +1,15 @@
1
1
  source "http://rubygems.org"
2
2
  gemspec
3
3
 
4
- gem 'arel', :git => 'git://github.com/rails/arel.git'
5
- gem 'rack', :git => 'git://github.com/rack/rack.git'
6
-
7
- git 'git://github.com/rails/rails.git' do
4
+ if ENV['RAILS_VERSION'] == 'release'
8
5
  gem 'activesupport'
9
6
  gem 'activerecord'
10
7
  gem 'actionpack'
11
- end
8
+ else
9
+ gem 'arel', :git => 'git://github.com/rails/arel.git'
10
+ git 'git://github.com/rails/rails.git' do
11
+ gem 'activesupport'
12
+ gem 'activerecord'
13
+ gem 'actionpack'
14
+ end
15
+ end
data/lib/ransack.rb CHANGED
@@ -2,6 +2,8 @@ require 'ransack/configuration'
2
2
 
3
3
  module Ransack
4
4
  extend Configuration
5
+
6
+ class UntraversableAssociationError < StandardError; end;
5
7
  end
6
8
 
7
9
  Ransack.configure do |config|
@@ -19,7 +19,6 @@ module Ransack
19
19
  Ransacker.new(self, name, opts, &block)
20
20
  end
21
21
 
22
- # TODO: Let's actually do some authorization. Whitelist-only.
23
22
  def ransackable_attributes(auth_object)
24
23
  column_names + _ransackers.keys
25
24
  end
@@ -69,8 +69,7 @@ module Ransack
69
69
  found_assoc = nil
70
70
  while remainder.unshift(segments.pop) && segments.size > 0 && !found_assoc do
71
71
  assoc, klass = unpolymorphize_association(segments.join('_'))
72
- if ransackable_association?(assoc, klassify(parent))
73
- found_assoc = get_association(assoc, parent)
72
+ if found_assoc = get_association(assoc, parent)
74
73
  join = build_or_find_association(found_assoc.name, parent, klass)
75
74
  parent, attr_name = get_parent_and_attribute_name(remainder.join('_'), join)
76
75
  end
@@ -80,16 +79,10 @@ module Ransack
80
79
  [parent, attr_name]
81
80
  end
82
81
 
83
- def ransackable_attribute?(str, klass)
84
- klass.ransackable_attributes(auth_object).include? str
85
- end
86
-
87
- def ransackable_association?(str, klass)
88
- klass.ransackable_associations(auth_object).include? str
89
- end
90
-
91
82
  def get_association(str, parent = @base)
92
- klassify(parent).reflect_on_all_associations.detect {|a| a.name.to_s == str}
83
+ klass = klassify parent
84
+ ransackable_association?(str, klass) &&
85
+ klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
93
86
  end
94
87
 
95
88
  def join_dependency(relation)
@@ -74,8 +74,7 @@ module Ransack
74
74
  found_assoc = nil
75
75
  while remainder.unshift(segments.pop) && segments.size > 0 && !found_assoc do
76
76
  assoc, klass = unpolymorphize_association(segments.join('_'))
77
- if ransackable_association?(assoc, klassify(parent))
78
- found_assoc = get_association(assoc, parent)
77
+ if found_assoc = get_association(assoc, parent)
79
78
  join = build_or_find_association(found_assoc.name, parent, klass)
80
79
  parent, attr_name = get_parent_and_attribute_name(remainder.join('_'), join)
81
80
  end
@@ -85,16 +84,10 @@ module Ransack
85
84
  [parent, attr_name]
86
85
  end
87
86
 
88
- def ransackable_attribute?(str, klass)
89
- klass.ransackable_attributes(auth_object).include? str
90
- end
91
-
92
- def ransackable_association?(str, klass)
93
- klass.ransackable_associations(auth_object).include? str
94
- end
95
-
96
87
  def get_association(str, parent = @base)
97
- klassify(parent).reflect_on_all_associations.detect {|a| a.name.to_s == str}
88
+ klass = klassify parent
89
+ ransackable_association?(str, klass) &&
90
+ klass.reflect_on_all_associations.detect {|a| a.name.to_s == str}
98
91
  end
99
92
 
100
93
  def join_dependency(relation)
@@ -65,12 +65,14 @@ module Ransack
65
65
  association_parts = []
66
66
  found_assoc = nil
67
67
  while !found_assoc && segments.size > 0 && association_parts << segments.shift do
68
+ # Strip the _of_Model_type text from the association name, but hold
69
+ # onto it in klass, for use as the next base
68
70
  assoc, klass = unpolymorphize_association(association_parts.join('_'))
69
71
  if found_assoc = get_association(assoc, base)
70
72
  base = traverse(segments.join('_'), klass || found_assoc.klass)
71
73
  end
72
74
  end
73
- raise ArgumentError, "No association matches #{str}" unless found_assoc
75
+ raise UntraversableAssociationError, "No association matches #{str}" unless found_assoc
74
76
  end
75
77
 
76
78
  klassify(base)
@@ -104,9 +106,21 @@ module Ransack
104
106
  end
105
107
  end
106
108
 
109
+ def ransackable_attribute?(str, klass)
110
+ klass.ransackable_attributes(auth_object).include? str
111
+ end
112
+
113
+ def ransackable_association?(str, klass)
114
+ klass.ransackable_associations(auth_object).include? str
115
+ end
116
+
107
117
  def searchable_attributes(str = '')
108
118
  traverse(str).ransackable_attributes(auth_object)
109
119
  end
110
120
 
121
+ def searchable_associations(str = '')
122
+ traverse(str).ransackable_associations(auth_object)
123
+ end
124
+
111
125
  end
112
126
  end
@@ -22,19 +22,8 @@ module Ransack
22
22
  options[:include_blank] = true unless options.has_key?(:include_blank)
23
23
  bases = [''] + association_array(options[:associations])
24
24
  if bases.size > 1
25
- collection = bases.map do |base|
26
- [
27
- Translate.association(base, :context => object.context),
28
- object.context.searchable_attributes(base).map do |c|
29
- [
30
- attr_from_base_and_column(base, c),
31
- Translate.attribute(attr_from_base_and_column(base, c), :context => object.context)
32
- ]
33
- end
34
- ]
35
- end
36
25
  @template.grouped_collection_select(
37
- @object_name, :name, collection, :last, :first, :first, :last,
26
+ @object_name, :name, attribute_collection_for_bases(bases), :last, :first, :first, :last,
38
27
  objectify_options(options), @default_options.merge(html_options)
39
28
  )
40
29
  else
@@ -55,20 +44,9 @@ module Ransack
55
44
  raise ArgumentError, "sort_select must be called inside a search FormBuilder!" unless object.respond_to?(:context)
56
45
  options[:include_blank] = true unless options.has_key?(:include_blank)
57
46
  bases = [''] + association_array(options[:associations])
58
- if bases.any?
59
- collection = bases.map do |base|
60
- [
61
- Translate.association(base, :context => object.context),
62
- object.context.searchable_attributes(base).map do |c|
63
- [
64
- attr_from_base_and_column(base, c),
65
- Translate.attribute(attr_from_base_and_column(base, c), :context => object.context)
66
- ]
67
- end
68
- ]
69
- end
47
+ if bases.size > 1
70
48
  @template.grouped_collection_select(
71
- @object_name, :name, collection, :last, :first, :first, :last,
49
+ @object_name, :name, attribute_collection_for_bases(bases), :last, :first, :first, :last,
72
50
  objectify_options(options), @default_options.merge(html_options)
73
51
  ) + @template.collection_select(
74
52
  @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last,
@@ -159,7 +137,7 @@ module Ransack
159
137
  obj.map do |key, value|
160
138
  case value
161
139
  when Array, Hash
162
- bases_array(value, key.to_s)
140
+ association_array(value, key.to_s)
163
141
  else
164
142
  [key.to_s, [key, value].join('_')]
165
143
  end
@@ -173,6 +151,24 @@ module Ransack
173
151
  [base, column].reject {|v| v.blank?}.join('_')
174
152
  end
175
153
 
154
+ def attribute_collection_for_bases(bases)
155
+ bases.map do |base|
156
+ begin
157
+ [
158
+ Translate.association(base, :context => object.context),
159
+ object.context.searchable_attributes(base).map do |c|
160
+ [
161
+ attr_from_base_and_column(base, c),
162
+ Translate.attribute(attr_from_base_and_column(base, c), :context => object.context)
163
+ ]
164
+ end
165
+ ]
166
+ rescue UntraversableAssociationError => e
167
+ nil
168
+ end
169
+ end.compact
170
+ end
171
+
176
172
  end
177
173
  end
178
174
  end
@@ -1,3 +1,3 @@
1
1
  module Ransack
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ransack
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.1
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ernie Miller
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-18 00:00:00 Z
13
+ date: 2011-05-30 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -147,7 +147,6 @@ files:
147
147
  - spec/blueprints/tags.rb
148
148
  - spec/console.rb
149
149
  - spec/helpers/ransack_helper.rb
150
- - spec/playground.rb
151
150
  - spec/ransack/adapters/active_record/base_spec.rb
152
151
  - spec/ransack/adapters/active_record/context_spec.rb
153
152
  - spec/ransack/configuration_spec.rb
@@ -194,7 +193,6 @@ test_files:
194
193
  - spec/blueprints/tags.rb
195
194
  - spec/console.rb
196
195
  - spec/helpers/ransack_helper.rb
197
- - spec/playground.rb
198
196
  - spec/ransack/adapters/active_record/base_spec.rb
199
197
  - spec/ransack/adapters/active_record/context_spec.rb
200
198
  - spec/ransack/configuration_spec.rb
data/spec/playground.rb DELETED
@@ -1,37 +0,0 @@
1
- $VERBOSE = false
2
- require 'bundler'
3
- Bundler.setup
4
- require 'machinist/active_record'
5
- require 'sham'
6
- require 'faker'
7
-
8
- Dir[File.expand_path('../../spec/{helpers,support,blueprints}/*.rb', __FILE__)].each do |f|
9
- require f
10
- end
11
-
12
- Sham.define do
13
- name { Faker::Name.name }
14
- title { Faker::Lorem.sentence }
15
- body { Faker::Lorem.paragraph }
16
- salary {|index| 30000 + (index * 1000)}
17
- tag_name { Faker::Lorem.words(3).join(' ') }
18
- note { Faker::Lorem.words(7).join(' ') }
19
- end
20
-
21
- Schema.create
22
-
23
- require 'ransack'
24
-
25
- Article.joins{person.comments}.where{person.comments.body =~ '%hello%'}.to_sql
26
- # => "SELECT \"articles\".* FROM \"articles\" INNER JOIN \"people\" ON \"people\".\"id\" = \"articles\".\"person_id\" INNER JOIN \"comments\" ON \"comments\".\"person_id\" = \"people\".\"id\" WHERE \"comments\".\"body\" LIKE '%hello%'"
27
-
28
- Person.where{(id + 1) == 2}.first
29
- # => #<Person id: 1, parent_id: nil, name: "Aric Smith", salary: 31000>
30
-
31
- Person.where{(salary - 40000) < 0}.to_sql
32
- # => "SELECT \"people\".* FROM \"people\" WHERE \"people\".\"salary\" - 40000 < 0"
33
-
34
- p = Person.select{[id, name, salary, (salary + 1000).as('salary_after_increase')]}.first
35
- # => #<Person id: 1, name: "Aric Smith", salary: 31000>
36
-
37
- p.salary_after_increase # =>