Commit d07e3bd16b6055a3ba50703b0b02103d7ea5ffab
1 parent
3e5043a1
Exists in
master
and in
29 other branches
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
Showing
8 changed files
with
87 additions
and
29 deletions
Show diff stats
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
config/environment.rb
| ... | ... | @@ -103,6 +103,7 @@ require 'acts_as_having_settings' |
| 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 < 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 < 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 < 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 < 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') | ... | ... |