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,20 +89,20 @@ class SearchController < ApplicationController | ||
| 89 | def load_product_categories_menu(asset) | 89 | def load_product_categories_menu(asset) |
| 90 | @results[asset].uniq! | 90 | @results[asset].uniq! |
| 91 | @categories_menu = ProductCategory.menu_categories(@product_category, environment).map do |cat| | 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 | childs = [] | 93 | childs = [] |
| 94 | # REFACTOR DUPLICATED CODE inner loop doing the same thing that outter loop | 94 | # REFACTOR DUPLICATED CODE inner loop doing the same thing that outter loop |
| 95 | childs = cat.children.map do |child| | 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 | [child, child_hits] | 97 | [child, child_hits] |
| 98 | end.select{|child, child_hits| child_hits > 0 } | 98 | end.select{|child, child_hits| child_hits > 0 } |
| 99 | [cat, hits, childs] | 99 | [cat, hits, childs] |
| 100 | end.select{|cat, hits| hits > 0 } | 100 | end.select{|cat, hits| hits > 0 } |
| 101 | end | 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 | if [:enterprises, :people].include?(asset) && region | 106 | if [:enterprises, :people].include?(asset) && region |
| 107 | result.merge!(:within => radius, :region => region.id) | 107 | result.merge!(:within => radius, :region => region.id) |
| 108 | end | 108 | end |
| @@ -110,6 +110,12 @@ class SearchController < ApplicationController | @@ -110,6 +110,12 @@ class SearchController < ApplicationController | ||
| 110 | result | 110 | result |
| 111 | end | 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 | public | 119 | public |
| 114 | 120 | ||
| 115 | include SearchHelper | 121 | include SearchHelper |
| @@ -125,9 +131,6 @@ class SearchController < ApplicationController | @@ -125,9 +131,6 @@ class SearchController < ApplicationController | ||
| 125 | [ :events, N_('Events') ] | 131 | [ :events, N_('Events') ] |
| 126 | ] | 132 | ] |
| 127 | 133 | ||
| 128 | - # TODO don't hardcode like this >:-( | ||
| 129 | - LIST_LIMIT = 10 | ||
| 130 | - | ||
| 131 | def complete_region | 134 | def complete_region |
| 132 | # FIXME this logic should be in the model | 135 | # FIXME this logic should be in the model |
| 133 | @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 + '%' ]) | 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,16 +148,11 @@ class SearchController < ApplicationController | ||
| 145 | # how many assets we are searching for? | 148 | # how many assets we are searching for? |
| 146 | number_of_result_assets = @searching.values.select{|v| v}.size | 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 | @results = {} | 151 | @results = {} |
| 154 | @names = {} | 152 | @names = {} |
| 155 | 153 | ||
| 156 | SEARCH_IN.select { |key,description| @searching[key] }.each do |key, description| | 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 | @names[key] = gettext(description) | 156 | @names[key] = gettext(description) |
| 159 | end | 157 | end |
| 160 | 158 |
app/models/category_finder.rb
| @@ -7,8 +7,6 @@ class CategoryFinder | @@ -7,8 +7,6 @@ class CategoryFinder | ||
| 7 | 7 | ||
| 8 | attr_reader :category_id | 8 | attr_reader :category_id |
| 9 | 9 | ||
| 10 | - | ||
| 11 | - | ||
| 12 | def find(asset, query='', options={}) | 10 | def find(asset, query='', options={}) |
| 13 | @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) | 11 | @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) |
| 14 | if @region && options[:within] | 12 | if @region && options[:within] |
| @@ -17,10 +15,12 @@ class CategoryFinder | @@ -17,10 +15,12 @@ class CategoryFinder | ||
| 17 | options.delete(:within) | 15 | options.delete(:within) |
| 18 | end | 16 | end |
| 19 | 17 | ||
| 18 | + options = {:page => 1, :per_page => options.delete(:limit)}.merge(options) | ||
| 20 | if query.blank? | 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 | else | 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 | end | 24 | end |
| 25 | end | 25 | end |
| 26 | 26 | ||
| @@ -33,8 +33,10 @@ class CategoryFinder | @@ -33,8 +33,10 @@ class CategoryFinder | ||
| 33 | end | 33 | end |
| 34 | 34 | ||
| 35 | def count(asset, query='', options={}) | 35 | def count(asset, query='', options={}) |
| 36 | + # because will_paginate needs a page | ||
| 37 | + options = {:page => 1}.merge(options) | ||
| 36 | if query.blank? | 38 | if query.blank? |
| 37 | - find(asset, query, options).size | 39 | + find(asset, query, options).total_entries |
| 38 | else | 40 | else |
| 39 | find(asset, query, options).total_hits | 41 | find(asset, query, options).total_hits |
| 40 | end | 42 | end |
app/models/environment_finder.rb
| @@ -15,22 +15,25 @@ class EnvironmentFinder | @@ -15,22 +15,25 @@ class EnvironmentFinder | ||
| 15 | product_category = options.delete(:product_category) | 15 | product_category = options.delete(:product_category) |
| 16 | product_category_ids = product_category.map_traversal(&:id) if product_category | 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 | if query.blank? | 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 | else | 28 | else |
| 29 | + ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} | ||
| 27 | if product_category && asset == :products | 30 | if product_category && asset == :products |
| 28 | # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source | 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 | elsif product_category && asset == :enterprises | 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 | else | 35 | else |
| 33 | - @environment.send(asset).find_by_contents(query, {}, options) | 36 | + @environment.send(asset).find_by_contents(query, ferret_options, options) |
| 34 | end | 37 | end |
| 35 | end | 38 | end |
| 36 | end | 39 | end |
| @@ -44,9 +47,11 @@ class EnvironmentFinder | @@ -44,9 +47,11 @@ class EnvironmentFinder | ||
| 44 | end | 47 | end |
| 45 | 48 | ||
| 46 | def count(asset, query = '', options = {}) | 49 | def count(asset, query = '', options = {}) |
| 50 | + # because will_paginate needs a page | ||
| 51 | + options = {:page => 1}.merge(options) | ||
| 47 | if query.blank? | 52 | if query.blank? |
| 48 | # SLOW | 53 | # SLOW |
| 49 | - find(asset, query, options).size | 54 | + find(asset, query, options).total_entries |
| 50 | else | 55 | else |
| 51 | find(asset, query, options).total_hits | 56 | find(asset, query, options).total_hits |
| 52 | end | 57 | end |
app/views/search/products.rhtml
config/environment.rb
| @@ -103,6 +103,7 @@ require 'acts_as_having_settings' | @@ -103,6 +103,7 @@ require 'acts_as_having_settings' | ||
| 103 | require 'acts_as_having_image' | 103 | require 'acts_as_having_image' |
| 104 | require 'hacked_after_create' | 104 | require 'hacked_after_create' |
| 105 | require 'sqlite_extension' | 105 | require 'sqlite_extension' |
| 106 | +require 'will_paginate' | ||
| 106 | 107 | ||
| 107 | # load a local configuration if present, but not under test environment. | 108 | # load a local configuration if present, but not under test environment. |
| 108 | if ENV['RAILS_ENV'] != 'test' | 109 | if ENV['RAILS_ENV'] != 'test' |
test/functional/search_controller_test.rb
| @@ -283,6 +283,16 @@ class SearchControllerTest < Test::Unit::TestCase | @@ -283,6 +283,16 @@ class SearchControllerTest < Test::Unit::TestCase | ||
| 283 | assert_equal [prod1], assigns(:results)[:products] | 283 | assert_equal [prod1], assigns(:results)[:products] |
| 284 | end | 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 | should 'display search results' do | 296 | should 'display search results' do |
| 287 | ent = Enterprise.create!(:name => 'display enterprise', :identifier => 'teste1') | 297 | ent = Enterprise.create!(:name => 'display enterprise', :identifier => 'teste1') |
| 288 | product = ent.products.create!(:name => 'display product') | 298 | product = ent.products.create!(:name => 'display product') |
test/unit/category_finder_test.rb
| @@ -151,6 +151,24 @@ class CategoryFinderTest < ActiveSupport::TestCase | @@ -151,6 +151,24 @@ class CategoryFinderTest < ActiveSupport::TestCase | ||
| 151 | assert_includes recent, ent2 | 151 | assert_includes recent, ent2 |
| 152 | assert_not_includes recent, ent1 | 152 | assert_not_includes recent, ent1 |
| 153 | end | 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 | should 'count enterprises' do | 173 | should 'count enterprises' do |
| 156 | count = @finder.count('enterprises') | 174 | count = @finder.count('enterprises') |
test/unit/environment_finder_test.rb
| @@ -49,6 +49,27 @@ class EnvironmentFinderTest < ActiveSupport::TestCase | @@ -49,6 +49,27 @@ class EnvironmentFinderTest < ActiveSupport::TestCase | ||
| 49 | recent = finder.recent('enterprises', 1) | 49 | recent = finder.recent('enterprises', 1) |
| 50 | assert_includes recent, ent2 # newer | 50 | assert_includes recent, ent2 # newer |
| 51 | assert_not_includes recent, ent1 # older | 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 | end | 73 | end |
| 53 | 74 | ||
| 54 | should 'count enterprises' do | 75 | should 'count enterprises' do |
| @@ -57,6 +78,7 @@ class EnvironmentFinderTest < ActiveSupport::TestCase | @@ -57,6 +78,7 @@ class EnvironmentFinderTest < ActiveSupport::TestCase | ||
| 57 | Enterprise.create!(:name => 'teste1', :identifier => 'teste1') | 78 | Enterprise.create!(:name => 'teste1', :identifier => 'teste1') |
| 58 | assert_equal count+1, finder.count('enterprises') | 79 | assert_equal count+1, finder.count('enterprises') |
| 59 | end | 80 | end |
| 81 | + | ||
| 60 | should 'count people' do | 82 | should 'count people' do |
| 61 | finder = EnvironmentFinder.new(Environment.default) | 83 | finder = EnvironmentFinder.new(Environment.default) |
| 62 | count = finder.count('people') | 84 | count = finder.count('people') |