meta_search 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ Changes since 0.5.0 (2010-06-08):
2
+ * Fix searching against relations derived from a has_many :through
3
+ association
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
@@ -37,7 +37,7 @@ module MetaSearch
37
37
  @relation = base_or_relation.scoped
38
38
  @base = @relation.klass
39
39
  @opts = opts
40
- @join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@base, @relation.joins_values, nil)
40
+ @join_dependency = build_join_dependency
41
41
  @search_attributes = {}
42
42
  end
43
43
 
@@ -134,6 +134,45 @@ module MetaSearch
134
134
  end
135
135
  end
136
136
 
137
+ def build_join_dependency
138
+ joins = @relation.joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
139
+
140
+ association_joins = joins.select do |j|
141
+ [Hash, Array, Symbol].include?(j.class) && !array_of_strings?(j)
142
+ end
143
+
144
+ stashed_association_joins = joins.select do |j|
145
+ j.is_a?(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)
146
+ end
147
+
148
+ non_association_joins = (joins - association_joins - stashed_association_joins)
149
+ custom_joins = custom_join_sql(*non_association_joins)
150
+
151
+ ActiveRecord::Associations::ClassMethods::JoinDependency.new(@base, association_joins, custom_joins)
152
+ end
153
+
154
+ def custom_join_sql(*joins)
155
+ arel = @relation.table
156
+ joins.each do |join|
157
+ next if join.blank?
158
+
159
+ case join
160
+ when Hash, Array, Symbol
161
+ if array_of_strings?(join)
162
+ join_string = join.join(' ')
163
+ arel = arel.join(join_string)
164
+ end
165
+ else
166
+ arel = arel.join(join)
167
+ end
168
+ end
169
+ arel.joins(arel)
170
+ end
171
+
172
+ def array_of_strings?(o)
173
+ o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
174
+ end
175
+
137
176
  def build_sort_method
138
177
  singleton_class.instance_eval do
139
178
  define_method(:meta_sort) do
@@ -2,15 +2,11 @@ require 'action_view'
2
2
  require 'action_view/template'
3
3
  module MetaSearch
4
4
  Check = Struct.new(:box, :label)
5
-
5
+
6
6
  module Helpers
7
7
  module FormBuilder
8
8
  extend ActiveSupport::Concern
9
-
10
- included do
11
- self.field_helpers += ['multiparameter_field', 'check_boxes', 'collection_check_boxes']
12
- end
13
-
9
+
14
10
  # Like other form_for field methods (text_field, hidden_field, password_field) etc,
15
11
  # but takes a list of hashes between the +method+ parameter and the trailing option hash,
16
12
  # if any, to specify a number of fields to create in multiparameter fashion.
@@ -55,7 +51,7 @@ module MetaSearch
55
51
  end
56
52
  html
57
53
  end
58
-
54
+
59
55
  # Behaves almost exactly like the select method, but instead of generating a select tag,
60
56
  # generates <tt>MetaSearch::Check</tt>s. These consist of two attributes, +box+ and +label+,
61
57
  # which are (unsurprisingly) the HTML for the check box and the label. Called without a block,
@@ -107,13 +103,13 @@ module MetaSearch
107
103
  end
108
104
  collection_check_boxes(method, choices, :last, :first, options, &block)
109
105
  end
110
-
106
+
111
107
  # Just like +check_boxes+, but this time you can pass in a collection, value, and text method,
112
108
  # as with collection_select.
113
109
  #
114
110
  # Example:
115
111
  #
116
- # <%= f.collection_check_boxes :head_sizes_in, HeadSize.all,
112
+ # <% f.collection_check_boxes :head_sizes_in, HeadSize.all,
117
113
  # :id, :name, :class => 'headcheck' do |check| %>
118
114
  # <%= check.box %> <%= check.label %>
119
115
  # <% end %>
@@ -139,9 +135,9 @@ module MetaSearch
139
135
  end
140
136
  check_boxes unless block_given?
141
137
  end
142
-
138
+
143
139
  private
144
-
140
+
145
141
  # If the last element of the arguments to multiparameter_field has no :field_type
146
142
  # key, we assume it's got some defaults to be used in the other hashes.
147
143
  def has_multiparameter_defaults?(args)
data/meta_search.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{meta_search}
8
- s.version = "0.5.0"
8
+ s.version = "0.5.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ernie Miller"]
12
- s.date = %q{2010-06-08}
12
+ s.date = %q{2010-07-20}
13
13
  s.description = %q{
14
14
  Allows simple search forms to be created against an AR3 model
15
15
  and its associations, has useful view helpers for sort links
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
24
24
  ".document",
25
25
  ".gitignore",
26
26
  ".gitmodules",
27
+ "CHANGELOG",
27
28
  "Gemfile",
28
29
  "LICENSE",
29
30
  "README.rdoc",
data/test/helper.rb CHANGED
@@ -15,7 +15,7 @@ ActiveRecord::Base.establish_connection(
15
15
  )
16
16
 
17
17
  dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
18
- dep.load_paths.unshift FIXTURES_PATH
18
+ dep.autoload_paths.unshift FIXTURES_PATH
19
19
 
20
20
  ActiveRecord::Base.silence do
21
21
  ActiveRecord::Migration.verbose = false
data/test/test_search.rb CHANGED
@@ -562,4 +562,42 @@ class TestSearch < Test::Unit::TestCase
562
562
  end
563
563
  end
564
564
  end
565
+
566
+ context_a_search_against "a relation derived from a joined association",
567
+ Company.where(:name => "Initech").first.developers do
568
+ should "not raise an error" do
569
+ assert_nothing_raised do
570
+ @s.all
571
+ end
572
+ end
573
+
574
+ should "return all developers for that company without conditions" do
575
+ assert_equal Company.where(:name => 'Initech').first.developers.all, @s.all
576
+ end
577
+
578
+ should "allow conditions on the search" do
579
+ @s.name_equals = 'Peter Gibbons'
580
+ assert_equal Developer.where(:name => 'Peter Gibbons').first,
581
+ @s.first
582
+ end
583
+ end
584
+
585
+ context_a_search_against "a relation derived from a joined HM:T association",
586
+ Company.where(:name => "Initech").first.developer_notes do
587
+ should "not raise an error" do
588
+ assert_nothing_raised do
589
+ @s.all
590
+ end
591
+ end
592
+
593
+ should "return all developer notes for that company without conditions" do
594
+ assert_equal Company.where(:name => 'Initech').first.developer_notes.all, @s.all
595
+ end
596
+
597
+ should "allow conditions on the search" do
598
+ @s.note_equals = 'A straight shooter with upper management written all over him.'
599
+ assert_equal Note.where(:note => 'A straight shooter with upper management written all over him.').first,
600
+ @s.first
601
+ end
602
+ end
565
603
  end
@@ -5,7 +5,7 @@ require 'action_view/test_case'
5
5
  class TestViewHelpers < ActionView::TestCase
6
6
  tests MetaSearch::Helpers::FormHelper
7
7
  include MetaSearch::Helpers::UrlHelper
8
-
8
+
9
9
  router = ActionDispatch::Routing::RouteSet.new
10
10
  router.draw do |map|
11
11
  resources :developers
@@ -15,23 +15,23 @@ class TestViewHelpers < ActionView::TestCase
15
15
  match ':controller(/:action(/:id(.:format)))'
16
16
  end
17
17
  include router.url_helpers
18
-
18
+
19
19
  def setup
20
20
  @controller = Class.new do
21
-
21
+
22
22
  attr_reader :url_for_options
23
23
  def url_for(options)
24
24
  @url_for_options = options
25
25
  "http://www.example.com"
26
26
  end
27
-
28
- def _router
29
- @router ||= ActionDispatch::Routing::RouteSet.new
27
+
28
+ def _routes
29
+ @routes ||= ActionDispatch::Routing::RouteSet.new
30
30
  end
31
31
  end
32
32
  @controller = @controller.new
33
33
  end
34
-
34
+
35
35
  context "A previously-filled search form" do
36
36
  setup do
37
37
  @s = Company.search
@@ -54,7 +54,7 @@ class TestViewHelpers < ActionView::TestCase
54
54
  @f.text_field(:name_contains)
55
55
  end
56
56
  end
57
-
57
+
58
58
  context "A form using mutiparameter_field with default size option" do
59
59
  setup do
60
60
  @s = Developer.search
@@ -62,9 +62,9 @@ class TestViewHelpers < ActionView::TestCase
62
62
  @f = f
63
63
  end
64
64
  end
65
-
65
+
66
66
  should "apply proper cast and default size attribute to text fields" do
67
- html = @f.multiparameter_field :salary_in,
67
+ html = @f.multiparameter_field :salary_in,
68
68
  {:field_type => :text_field, :type_cast => 'i'},
69
69
  {:field_type => :text_field, :type_cast => 'i'}, :size => 10
70
70
  assert_dom_equal '<input id="search_salary_in(1i)" name="search[salary_in(1i)]" ' +
@@ -74,7 +74,7 @@ class TestViewHelpers < ActionView::TestCase
74
74
  html
75
75
  end
76
76
  end
77
-
77
+
78
78
  context "A form using check_boxes with three choices" do
79
79
  setup do
80
80
  @s = Company.search
@@ -82,11 +82,11 @@ class TestViewHelpers < ActionView::TestCase
82
82
  @f = f
83
83
  end
84
84
  end
85
-
85
+
86
86
  should "return an array of check boxes without a block" do
87
87
  assert @f.check_boxes(:id_in, [['One', 1], ['Two', 2], ['Three', 3]]).all?{|c| c.is_a?(MetaSearch::Check)}
88
88
  end
89
-
89
+
90
90
  should "generate the expected HTML with a block" do
91
91
  expected = <<-EXPECTED
92
92
  <p>
@@ -113,7 +113,7 @@ class TestViewHelpers < ActionView::TestCase
113
113
  ERB
114
114
  end
115
115
  end
116
-
116
+
117
117
  context "A form using check_boxes with three choices and a previous selection" do
118
118
  setup do
119
119
  @s = Company.search
@@ -122,11 +122,11 @@ class TestViewHelpers < ActionView::TestCase
122
122
  @f = f
123
123
  end
124
124
  end
125
-
125
+
126
126
  should "return an array of check boxes without a block" do
127
127
  assert @f.check_boxes(:id_in, [['One', 1], ['Two', 2], ['Three', 3]]).all?{|c| c.is_a?(MetaSearch::Check)}
128
128
  end
129
-
129
+
130
130
  should "generate the expected HTML with a block" do
131
131
  expected = <<-EXPECTED
132
132
  <p>
@@ -152,7 +152,7 @@ class TestViewHelpers < ActionView::TestCase
152
152
  <% end -%>
153
153
  ERB
154
154
  end
155
-
155
+
156
156
  context "A form using collection_check_boxes with companies" do
157
157
  setup do
158
158
  @s = Company.search
@@ -160,11 +160,11 @@ class TestViewHelpers < ActionView::TestCase
160
160
  @f = f
161
161
  end
162
162
  end
163
-
163
+
164
164
  should "return an array of check boxes without a block" do
165
165
  assert @f.collection_check_boxes(:id_in, Company.all, :id, :name).all?{|c| c.is_a?(MetaSearch::Check)}
166
166
  end
167
-
167
+
168
168
  should "generate the expected HTML with a block" do
169
169
  @f.collection_check_boxes(:id_in, Company.all, :id, :name) do |c|
170
170
  concat render :to => :string, :inline => "<p><%= c.label %> <%= c.box %></p>", :locals => {:c => c}
@@ -179,32 +179,32 @@ class TestViewHelpers < ActionView::TestCase
179
179
  end
180
180
  end
181
181
  end
182
-
182
+
183
183
  context "A company search" do
184
184
  setup do
185
185
  @s = Company.search
186
186
  end
187
-
187
+
188
188
  context "sorted by name ascending" do
189
189
  setup do
190
190
  @s.meta_sort = 'name.asc'
191
191
  end
192
-
192
+
193
193
  should "generate a sort link with an up arrow for the sorted column" do
194
194
  assert_match /Name &#9650;/,
195
195
  sort_link(@s, :name, :controller => 'companies')
196
196
  end
197
-
197
+
198
198
  should "not generate a sort link with an up arrow for a non-sorted column" do
199
199
  assert_no_match /Created at &#9650;/,
200
200
  sort_link(@s, :created_at, :controller => 'companies')
201
201
  end
202
-
202
+
203
203
  context "with existing search options" do
204
204
  setup do
205
205
  @s.name_contains = 'a'
206
206
  end
207
-
207
+
208
208
  should "maintain previous search options in its sort links" do
209
209
  assert_match /search\[name_contains\]=a/,
210
210
  sort_link(@s, :name, :controller => 'companies')
@@ -212,32 +212,32 @@ class TestViewHelpers < ActionView::TestCase
212
212
  end
213
213
  end
214
214
  end
215
-
215
+
216
216
  context "A developer search" do
217
217
  setup do
218
218
  @s = Developer.search
219
219
  end
220
-
220
+
221
221
  context "sorted by company name descending" do
222
222
  setup do
223
223
  @s.meta_sort = 'company_name.desc'
224
224
  end
225
-
225
+
226
226
  should "generate a sort link with a down arrow for the sorted column" do
227
227
  assert_match /Company name &#9660;/,
228
228
  sort_link(@s, :company_name, :controller => 'developers')
229
229
  end
230
-
230
+
231
231
  should "not generate a sort link with a down arrow for a non-sorted column" do
232
232
  assert_no_match /Created at &#9660;/,
233
233
  sort_link(@s, :created_at, :controller => 'developers')
234
234
  end
235
-
235
+
236
236
  context "with existing search options" do
237
237
  setup do
238
238
  @s.name_contains = 'a'
239
239
  end
240
-
240
+
241
241
  should "maintain previous search options in its sort links" do
242
242
  assert_match /search\[name_contains\]=a/,
243
243
  sort_link(@s, :company_name, :controller => 'companies')
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 5
8
- - 0
9
- version: 0.5.0
8
+ - 1
9
+ version: 0.5.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ernie Miller
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-08 00:00:00 -04:00
17
+ date: 2010-07-20 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -106,6 +106,7 @@ files:
106
106
  - .document
107
107
  - .gitignore
108
108
  - .gitmodules
109
+ - CHANGELOG
109
110
  - Gemfile
110
111
  - LICENSE
111
112
  - README.rdoc