meta_search 0.5.0 → 0.5.1

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/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