Commit d07e3bd16b6055a3ba50703b0b02103d7ea5ffab

Authored by MoisesMachado
1 parent 3e5043a1

ActionItem509: implemented pagination infrastructure only left put views helpers


git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@2137 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/public/search_controller.rb
... ... @@ -89,20 +89,20 @@ class SearchController < ApplicationController
89 89 def load_product_categories_menu(asset)
90 90 @results[asset].uniq!
91 91 @categories_menu = ProductCategory.menu_categories(@product_category, environment).map do |cat|
92   - hits = @finder.count(:products, @filtered_query, calculate_find_options(asset, nil, cat, @region, params[:radius]))
  92 + hits = @finder.count(:products, @filtered_query, calculate_find_options(asset, nil, nil, cat, @region, params[:radius]))
93 93 childs = []
94 94 # REFACTOR DUPLICATED CODE inner loop doing the same thing that outter loop
95 95 childs = cat.children.map do |child|
96   - child_hits = @finder.count(:products, @filtered_query, calculate_find_options(asset, nil, child, @region, params[:radius]))
  96 + child_hits = @finder.count(:products, @filtered_query, calculate_find_options(asset, nil, nil, child, @region, params[:radius]))
97 97 [child, child_hits]
98 98 end.select{|child, child_hits| child_hits > 0 }
99 99 [cat, hits, childs]
100 100 end.select{|cat, hits| hits > 0 }
101 101 end
102 102  
103   - def calculate_find_options(asset, limit, product_category, region, radius)
  103 + def calculate_find_options(asset, limit, page, product_category, region, radius)
104 104  
105   - result = { :limit => limit, :product_category => product_category}
  105 + result = { :product_category => product_category, :per_page => limit, :page => page }
106 106 if [:enterprises, :people].include?(asset) && region
107 107 result.merge!(:within => radius, :region => region.id)
108 108 end
... ... @@ -110,6 +110,12 @@ class SearchController < ApplicationController
110 110 result
111 111 end
112 112  
  113 + # limit the number of results per page
  114 + # TODO: dont hardcore like this
  115 + def limit
  116 + 10
  117 + end
  118 +
113 119 public
114 120  
115 121 include SearchHelper
... ... @@ -125,9 +131,6 @@ class SearchController < ApplicationController
125 131 [ :events, N_('Events') ]
126 132 ]
127 133  
128   - # TODO don't hardcode like this >:-(
129   - LIST_LIMIT = 10
130   -
131 134 def complete_region
132 135 # FIXME this logic should be in the model
133 136 @regions = Region.find(:all, :conditions => [ '(name like ? or name like ?) and lat is not null and lng is not null', '%' + params[:region][:name] + '%', '%' + params[:region][:name].capitalize + '%' ])
... ... @@ -145,16 +148,11 @@ class SearchController < ApplicationController
145 148 # how many assets we are searching for?
146 149 number_of_result_assets = @searching.values.select{|v| v}.size
147 150  
148   - # apply limit when searching for only one type of asset
149   - limit = (number_of_result_assets == 1) ? nil: LIST_LIMIT
150   - # apply limit to all searches
151   -# limit = nil
152   -
153 151 @results = {}
154 152 @names = {}
155 153  
156 154 SEARCH_IN.select { |key,description| @searching[key] }.each do |key, description|
157   - @results[key] = @finder.find(key, @filtered_query, calculate_find_options(key, limit, @product_category, @region, params[:radius]))
  155 + @results[key] = @finder.find(key, @filtered_query, calculate_find_options(key, limit, params[:page], @product_category, @region, params[:radius]))
158 156 @names[key] = gettext(description)
159 157 end
160 158  
... ...
app/models/category_finder.rb
... ... @@ -7,8 +7,6 @@ class CategoryFinder
7 7  
8 8 attr_reader :category_id
9 9  
10   -
11   -
12 10 def find(asset, query='', options={})
13 11 @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region)
14 12 if @region && options[:within]
... ... @@ -17,10 +15,12 @@ class CategoryFinder
17 15 options.delete(:within)
18 16 end
19 17  
  18 + options = {:page => 1, :per_page => options.delete(:limit)}.merge(options)
20 19 if query.blank?
21   - asset_class(asset).find(:all, options_for_find(asset_class(asset), {:order => "created_at desc, #{asset_table(asset)}.id desc"}.merge(options)))
  20 + asset_class(asset).paginate(:all, options_for_find(asset_class(asset), {:order => "created_at desc, #{asset_table(asset)}.id desc"}.merge(options)))
22 21 else
23   - asset_class(asset).find_by_contents(query, {}, options_for_find(asset_class(asset), options)).uniq
  22 + ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)}
  23 + asset_class(asset).find_by_contents(query, ferret_options, options_for_find(asset_class(asset), options)).uniq
24 24 end
25 25 end
26 26  
... ... @@ -33,8 +33,10 @@ class CategoryFinder
33 33 end
34 34  
35 35 def count(asset, query='', options={})
  36 + # because will_paginate needs a page
  37 + options = {:page => 1}.merge(options)
36 38 if query.blank?
37   - find(asset, query, options).size
  39 + find(asset, query, options).total_entries
38 40 else
39 41 find(asset, query, options).total_hits
40 42 end
... ...
app/models/environment_finder.rb
... ... @@ -15,22 +15,25 @@ class EnvironmentFinder
15 15 product_category = options.delete(:product_category)
16 16 product_category_ids = product_category.map_traversal(&:id) if product_category
17 17  
  18 + options = {:page => 1, :per_page => options.delete(:limit)}.merge(options)
18 19 if query.blank?
19   - if product_category && asset == :products
20   - @environment.send(asset).find(:all, options.merge({:order => 'created_at desc, id desc', :conditions => ['product_category_id in (?)', product_category_ids]}))
21   - elsif product_category && asset == :enterprises
22   - @environment.send(asset).find(:all, options.merge(:order => 'profiles.created_at desc, profiles.id desc', :include => 'products', :conditions => ['products.product_category_id in (?)', product_category_ids]))
23   - else
24   - @environment.send(asset).find( :all, options.merge( {:order => 'created_at desc, id desc'} ) )
25   - end
  20 + options = {:order => 'created_at desc, id desc'}.merge(options)
  21 + if product_category && asset == :products
  22 + @environment.send(asset).paginate(:all, options.merge(:conditions => ['product_category_id in (?)', product_category_ids]))
  23 + elsif product_category && asset == :enterprises
  24 + @environment.send(asset).paginate(:all, options.merge(:order => 'profiles.created_at desc, profiles.id desc', :include => 'products', :conditions => ['products.product_category_id in (?)', product_category_ids]))
  25 + else
  26 + @environment.send(asset).paginate(:all, options)
  27 + end
26 28 else
  29 + ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)}
27 30 if product_category && asset == :products
28 31 # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source
29   - @environment.send(asset).find_by_contents(query, {}, options.merge({:conditions => 'product_category_id in (%s)' % product_category_ids.join(',') }))
  32 + @environment.send(asset).find_by_contents(query, ferret_options, options.merge({:conditions => 'product_category_id in (%s)' % product_category_ids.join(',') }))
30 33 elsif product_category && asset == :enterprises
31   - @environment.send(asset).find_by_contents(query + " +extra_data_for_index:#{product_category.name}", {}, options)
  34 + @environment.send(asset).find_by_contents(query + " +extra_data_for_index:#{product_category.name}", ferret_options, options)
32 35 else
33   - @environment.send(asset).find_by_contents(query, {}, options)
  36 + @environment.send(asset).find_by_contents(query, ferret_options, options)
34 37 end
35 38 end
36 39 end
... ... @@ -44,9 +47,11 @@ class EnvironmentFinder
44 47 end
45 48  
46 49 def count(asset, query = '', options = {})
  50 + # because will_paginate needs a page
  51 + options = {:page => 1}.merge(options)
47 52 if query.blank?
48 53 # SLOW
49   - find(asset, query, options).size
  54 + find(asset, query, options).total_entries
50 55 else
51 56 find(asset, query, options).total_hits
52 57 end
... ...
app/views/search/products.rhtml
... ... @@ -29,4 +29,6 @@
29 29 </div>
30 30 </div>
31 31  
  32 +<%= will_paginate @results[:products], :id => 'products-pagination' %>
  33 +
32 34 <br style="clear:both" />
... ...
config/environment.rb
... ... @@ -103,6 +103,7 @@ require &#39;acts_as_having_settings&#39;
103 103 require 'acts_as_having_image'
104 104 require 'hacked_after_create'
105 105 require 'sqlite_extension'
  106 +require 'will_paginate'
106 107  
107 108 # load a local configuration if present, but not under test environment.
108 109 if ENV['RAILS_ENV'] != 'test'
... ...
test/functional/search_controller_test.rb
... ... @@ -283,6 +283,16 @@ class SearchControllerTest &lt; Test::Unit::TestCase
283 283 assert_equal [prod1], assigns(:results)[:products]
284 284 end
285 285  
  286 + should 'paginate enterprise listing' do
  287 + @controller.expects(:limit).returns(1)
  288 + ent1 = Enterprise.create!(:name => 'teste 1', :identifier => 'teste_1')
  289 + ent2 = Enterprise.create!(:name => 'teste 2', :identifier => 'teste_2')
  290 +
  291 + get :assets, :asset => 'enterprises', :page => '2'
  292 +
  293 + assert_equal [ent1], assigns(:results)[:enterprises] # older on page 2
  294 + end
  295 +
286 296 should 'display search results' do
287 297 ent = Enterprise.create!(:name => 'display enterprise', :identifier => 'teste1')
288 298 product = ent.products.create!(:name => 'display product')
... ...
test/unit/category_finder_test.rb
... ... @@ -151,6 +151,24 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase
151 151 assert_includes recent, ent2
152 152 assert_not_includes recent, ent1
153 153 end
  154 +
  155 + should 'paginate the list of more enterprises than limit' do
  156 + ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :category_ids => [@category.id])
  157 + ent2 = Enterprise.create!(:name => 'teste2', :identifier => 'teste2', :category_ids => [@category.id])
  158 +
  159 + assert_equal [ent2], @finder.find('enterprises', nil, :per_page => 1, :page => 1)
  160 + assert_equal [ent1], @finder.find('enterprises', nil, :per_page => 1, :page => 2)
  161 + end
  162 +
  163 + should 'paginate the list of more enterprises than limit with query' do
  164 + ent1 = Enterprise.create!(:name => 'teste 1', :identifier => 'teste1', :category_ids => [@category.id])
  165 + ent2 = Enterprise.create!(:name => 'teste 2', :identifier => 'teste2', :category_ids => [@category.id])
  166 +
  167 + p1 = @finder.find('enterprises', 'teste', :per_page => 1, :page => 1)
  168 + p2 = @finder.find('enterprises', 'teste', :per_page => 1, :page => 2)
  169 +
  170 + assert (p1 == [ent1] && p2 == [ent2]) || (p1 == [ent2] && p2 == [ent1]) # consistent paging
  171 + end
154 172  
155 173 should 'count enterprises' do
156 174 count = @finder.count('enterprises')
... ...
test/unit/environment_finder_test.rb
... ... @@ -49,6 +49,27 @@ class EnvironmentFinderTest &lt; ActiveSupport::TestCase
49 49 recent = finder.recent('enterprises', 1)
50 50 assert_includes recent, ent2 # newer
51 51 assert_not_includes recent, ent1 # older
  52 + end
  53 +
  54 + should 'paginate the list of more enterprises than limit' do
  55 + finder = EnvironmentFinder.new(Environment.default)
  56 + ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1')
  57 + ent2 = Enterprise.create!(:name => 'teste2', :identifier => 'teste2')
  58 +
  59 + assert_equal [ent2], finder.find('enterprises', nil, :per_page => 1, :page => 1) #newer
  60 + assert_equal [ent1], finder.find('enterprises', nil, :per_page => 1, :page => 2) #older
  61 + end
  62 +
  63 + should 'paginate the list of more enterprises than limit with query' do
  64 + finder = EnvironmentFinder.new(Environment.default)
  65 +
  66 + ent1 = Enterprise.create!(:name => 'teste 1', :identifier => 'teste1')
  67 + ent2 = Enterprise.create!(:name => 'teste 2', :identifier => 'teste2')
  68 +
  69 + p1 = finder.find('enterprises', 'teste', :per_page => 1, :page => 1)
  70 + p2 = finder.find('enterprises', 'teste', :per_page => 1, :page => 2)
  71 +
  72 + assert (p1 == [ent1] && p2 == [ent2]) || (p1 == [ent2] && p2 == [ent1])
52 73 end
53 74  
54 75 should 'count enterprises' do
... ... @@ -57,6 +78,7 @@ class EnvironmentFinderTest &lt; ActiveSupport::TestCase
57 78 Enterprise.create!(:name => 'teste1', :identifier => 'teste1')
58 79 assert_equal count+1, finder.count('enterprises')
59 80 end
  81 +
60 82 should 'count people' do
61 83 finder = EnvironmentFinder.new(Environment.default)
62 84 count = finder.count('people')
... ...