Commit d2e3b9ec048d4f8eaac95b5efc041458b894261e
1 parent
5cac53de
Exists in
master
and in
28 other branches
Search controller plugin test done
Showing
8 changed files
with
135 additions
and
122 deletions
Show diff stats
app/controllers/application_controller.rb
| ... | ... | @@ -154,20 +154,21 @@ class ApplicationController < ActionController::Base |
| 154 | 154 | end |
| 155 | 155 | end |
| 156 | 156 | |
| 157 | - def find_by_contents(scope, query, paginate_options={:page => 1}, options={}) | |
| 157 | + def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) | |
| 158 | 158 | scope = scope.send(options[:filter]) if options[:filter] |
| 159 | - return {:results => scope.paginate(paginate_options)} if query.blank? | |
| 160 | 159 | |
| 161 | - @plugins.first(:find_by_contents, scope, query, paginate_options, options) || | |
| 162 | - fallback_find_by_contents(scope, query, paginate_options, options) | |
| 160 | + @plugins.first(:find_by_contents, asset, scope, query, paginate_options, options) || | |
| 161 | + fallback_find_by_contents(asset, scope, query, paginate_options, options) | |
| 163 | 162 | end |
| 164 | 163 | |
| 165 | 164 | private |
| 166 | 165 | |
| 167 | - def fallback_find_by_contents(scope, query, paginate_options, options) | |
| 168 | - fields = scope.base_class::SEARCHABLE_FIELDS.keys.map(&:to_s) & scope.base_class.column_names | |
| 166 | + def fallback_find_by_contents(asset, scope, query, paginate_options, options) | |
| 167 | + return {:results => scope.paginate(paginate_options)} if query.blank? | |
| 168 | + klass = asset.to_s.singularize.camelize.constantize | |
| 169 | + fields = klass::SEARCHABLE_FIELDS.keys.map(&:to_s) & klass.column_names | |
| 169 | 170 | conditions = fields.map do |field| |
| 170 | - "lower(#{scope.base_class.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" | |
| 171 | + "lower(#{klass.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" | |
| 171 | 172 | end.join(' OR ') |
| 172 | 173 | {:results => scope.where(conditions).paginate(paginate_options)} |
| 173 | 174 | end | ... | ... |
app/controllers/public/search_controller.rb
| ... | ... | @@ -211,7 +211,7 @@ class SearchController < PublicController |
| 211 | 211 | end |
| 212 | 212 | |
| 213 | 213 | def full_text_search |
| 214 | - @searches[@asset] = find_by_contents(@scope, @query, paginate_options, {:category => @category, :filter => @filter}) | |
| 214 | + @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter}) | |
| 215 | 215 | end |
| 216 | 216 | |
| 217 | 217 | private | ... | ... |
lib/noosfero/plugin.rb
| ... | ... | @@ -355,7 +355,7 @@ class Noosfero::Plugin |
| 355 | 355 | # returns = {:results => [a, b, c, ...], ...} |
| 356 | 356 | # P.S.: The plugin might add other informations on the return hash for its |
| 357 | 357 | # own use in specific views |
| 358 | - def find_by_contents(klass, query, paginate_options={}, options={}) | |
| 358 | + def find_by_contents(asset, klass, query, paginate_options={}, options={}) | |
| 359 | 359 | end |
| 360 | 360 | |
| 361 | 361 | def method_missing(method, *args, &block) | ... | ... |
plugins/solr/lib/solr_plugin.rb
| ... | ... | @@ -20,11 +20,15 @@ class SolrPlugin < Noosfero::Plugin |
| 20 | 20 | true |
| 21 | 21 | end |
| 22 | 22 | |
| 23 | - def find_by_contents(klass, query, paginate_options={}, options={}) | |
| 23 | + def find_by_contents(asset, scope, query, paginate_options={}, options={}) | |
| 24 | + klass = asset_class(asset) | |
| 24 | 25 | category = options.delete(:category) |
| 25 | 26 | filter = options.delete(:filter) |
| 27 | + | |
| 28 | + return if empty_query?(query, category) && klass != Product | |
| 29 | + | |
| 26 | 30 | solr_options = solr_options(class_asset(klass), category) |
| 27 | - user = context.respond_to?(:user) ? context.send(:user) : nil | |
| 31 | + user = context.send(:logged_in?) ? context.send(:user) : nil | |
| 28 | 32 | solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) |
| 29 | 33 | klass.find_by_contents(query, paginate_options, solr_options.merge(options)) |
| 30 | 34 | end | ... | ... |
plugins/solr/lib/solr_plugin/search_helper.rb
| ... | ... | @@ -45,15 +45,11 @@ module SolrPlugin::SearchHelper |
| 45 | 45 | def asset_table(asset) |
| 46 | 46 | asset_class(asset).table_name |
| 47 | 47 | end |
| 48 | -# | |
| 49 | -# def multiple_search? | |
| 50 | -# ['index', 'category_index'].include?(context.params[:action]) | |
| 51 | -# end | |
| 52 | 48 | |
| 53 | 49 | def filters(asset) |
| 54 | 50 | case asset |
| 55 | 51 | when :products |
| 56 | - ['solr_plugin_public:true'] | |
| 52 | + ['solr_plugin_public:true', 'enabled:true'] | |
| 57 | 53 | when :events |
| 58 | 54 | [] |
| 59 | 55 | else |
| ... | ... | @@ -69,6 +65,24 @@ module SolrPlugin::SearchHelper |
| 69 | 65 | category.nil? && query.blank? |
| 70 | 66 | end |
| 71 | 67 | |
| 68 | + def products_options(person) | |
| 69 | + geosearch = person && person.lat && person.lng | |
| 70 | + | |
| 71 | + extra_limit = LIST_SEARCH_LIMIT*5 | |
| 72 | + sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | |
| 73 | + options = {:sql_options => sql_options, :extra_limit => extra_limit} | |
| 74 | + | |
| 75 | + if geosearch | |
| 76 | + options.merge({ | |
| 77 | + :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", | |
| 78 | + :radius => DistFilt, | |
| 79 | + :latitude => person.lat, | |
| 80 | + :longitude => person.lng }) | |
| 81 | + else | |
| 82 | + options.merge({:boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']}) | |
| 83 | + end | |
| 84 | + end | |
| 85 | + | |
| 72 | 86 | def solr_options(asset, category) |
| 73 | 87 | asset_class = asset_class(asset) |
| 74 | 88 | solr_options = {} |
| ... | ... | @@ -95,21 +109,6 @@ module SolrPlugin::SearchHelper |
| 95 | 109 | solr_options |
| 96 | 110 | end |
| 97 | 111 | |
| 98 | - def products_options(person) | |
| 99 | - geosearch = person && person.lat && person.lng | |
| 100 | - | |
| 101 | - extra_limit = LIST_SEARCH_LIMIT*5 | |
| 102 | - sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | |
| 103 | - if geosearch | |
| 104 | - {:sql_options => sql_options, :extra_limit => extra_limit, | |
| 105 | - :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", | |
| 106 | - :radius => DistFilt, :latitude => person.lat, :longitude => person.lng} | |
| 107 | - else | |
| 108 | - { :sql_options => sql_options, :extra_limit => extra_limit, | |
| 109 | - :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']} | |
| 110 | - end | |
| 111 | - end | |
| 112 | - | |
| 113 | 112 | def asset_class(asset) |
| 114 | 113 | asset.to_s.singularize.camelize.constantize |
| 115 | 114 | end | ... | ... |
plugins/solr/test/functional/search_controller_test.rb
| 1 | 1 | require 'test_helper' |
| 2 | -require 'test_solr_helper' | |
| 2 | +require File.dirname(__FILE__) + '/../test_solr_helper' | |
| 3 | 3 | require File.dirname(__FILE__) + '/../../lib/ext/facets_browse' |
| 4 | 4 | |
| 5 | 5 | # Re-raise errors caught by the controller. |
| ... | ... | @@ -108,7 +108,7 @@ class SearchControllerTest < ActionController::TestCase |
| 108 | 108 | prod2 = ent2.products.create!(:name => 'another beautiful product', :product_category => @product_category) |
| 109 | 109 | |
| 110 | 110 | get :products |
| 111 | - assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results] | |
| 111 | + assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results].docs | |
| 112 | 112 | assert_match 'Highlights', @response.body |
| 113 | 113 | end |
| 114 | 114 | |
| ... | ... | @@ -156,45 +156,45 @@ class SearchControllerTest < ActionController::TestCase |
| 156 | 156 | end |
| 157 | 157 | |
| 158 | 158 | # Testing random sequences always have a small chance of failing |
| 159 | -# should 'randomize product display in empty search' do | |
| 160 | -# prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) | |
| 161 | -# ent = create_profile_with_optional_category(Enterprise, 'test enterprise') | |
| 162 | -# (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| | |
| 163 | -# fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) | |
| 164 | -# end | |
| 165 | -# | |
| 166 | -# get :products | |
| 167 | -# result1 = assigns(:searches)[:products][:results].map(&:id) | |
| 168 | -# | |
| 169 | -# (1..10).each do |n| | |
| 170 | -# get :products | |
| 171 | -# end | |
| 172 | -# result2 = assigns(:searches)[:products][:results].map(&:id) | |
| 173 | -# | |
| 174 | -# assert_not_equal result1, result2 | |
| 175 | -# end | |
| 176 | -# | |
| 177 | -# should 'remove far products by geolocalization empty logged search' do | |
| 178 | -# user = create_user('a_logged_user') | |
| 179 | -# # trigger geosearch | |
| 180 | -# user.person.lat = '1.0' | |
| 181 | -# user.person.lng = '1.0' | |
| 182 | -# SearchController.any_instance.stubs(:logged_in?).returns(true) | |
| 183 | -# SearchController.any_instance.stubs(:current_user).returns(user) | |
| 184 | -# | |
| 185 | -# cat = fast_create(ProductCategory) | |
| 186 | -# ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') | |
| 187 | -# prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) | |
| 188 | -# ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') | |
| 189 | -# prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) | |
| 190 | -# ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') | |
| 191 | -# prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) | |
| 192 | -# ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') | |
| 193 | -# prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) | |
| 194 | -# | |
| 195 | -# get :products | |
| 196 | -# assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results] | |
| 197 | -# end | |
| 159 | + should 'randomize product display in empty search' do | |
| 160 | + prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) | |
| 161 | + ent = create_profile_with_optional_category(Enterprise, 'test enterprise') | |
| 162 | + (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| | |
| 163 | + fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) | |
| 164 | + end | |
| 165 | + | |
| 166 | + get :products | |
| 167 | + result1 = assigns(:searches)[:products][:results].map(&:id) | |
| 168 | + | |
| 169 | + (1..10).each do |n| | |
| 170 | + get :products | |
| 171 | + end | |
| 172 | + result2 = assigns(:searches)[:products][:results].map(&:id) | |
| 173 | + | |
| 174 | + assert_not_equal result1, result2 | |
| 175 | + end | |
| 176 | + | |
| 177 | + should 'remove far products by geolocalization empty logged search' do | |
| 178 | + user = create_user('a_logged_user') | |
| 179 | + # trigger geosearch | |
| 180 | + user.person.lat = '1.0' | |
| 181 | + user.person.lng = '1.0' | |
| 182 | + SearchController.any_instance.stubs(:logged_in?).returns(true) | |
| 183 | + SearchController.any_instance.stubs(:current_user).returns(user) | |
| 184 | + | |
| 185 | + cat = fast_create(ProductCategory) | |
| 186 | + ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') | |
| 187 | + prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) | |
| 188 | + ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') | |
| 189 | + prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) | |
| 190 | + ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') | |
| 191 | + prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) | |
| 192 | + ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') | |
| 193 | + prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) | |
| 194 | + | |
| 195 | + get :products | |
| 196 | + assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results].docs | |
| 197 | + end | |
| 198 | 198 | |
| 199 | 199 | should 'browse facets when query is not empty' do |
| 200 | 200 | get :articles, :query => 'something' | ... | ... |
| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | +class ActsAsSolr::Post | |
| 2 | + class << self | |
| 3 | + alias_method :execute_orig, :execute | |
| 4 | + end | |
| 5 | +end | |
| 6 | +module ActsAsSolr::ParserMethods | |
| 7 | + alias_method :parse_results_orig, :parse_results | |
| 8 | +end | |
| 9 | + | |
| 10 | +class TestSolr | |
| 11 | + | |
| 12 | + def self.enable | |
| 13 | + ActsAsSolr::Post.class_eval do | |
| 14 | + def self.execute(*args) | |
| 15 | + execute_orig *args | |
| 16 | + end | |
| 17 | + end | |
| 18 | + ActsAsSolr::ParserMethods.module_eval do | |
| 19 | + def parse_results(*args) | |
| 20 | + parse_results_orig *args | |
| 21 | + end | |
| 22 | + end | |
| 23 | + | |
| 24 | + # clear index | |
| 25 | + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) | |
| 26 | + | |
| 27 | + @solr_disabled = false | |
| 28 | + end | |
| 29 | + | |
| 30 | + def self.disable | |
| 31 | + return if @solr_disabled | |
| 32 | + | |
| 33 | + ActsAsSolr::Post.class_eval do | |
| 34 | + def self.execute(*args) | |
| 35 | + true | |
| 36 | + end | |
| 37 | + end | |
| 38 | + ActsAsSolr::ParserMethods.module_eval do | |
| 39 | + def parse_results(*args) | |
| 40 | + parse_results_orig nil, args[1] | |
| 41 | + end | |
| 42 | + end | |
| 43 | + | |
| 44 | + @solr_disabled = true | |
| 45 | + end | |
| 46 | + | |
| 47 | +end | |
| 48 | + | |
| 49 | +class ActiveSupport::TestCase | |
| 50 | + def fast_create_with_solr(name, attrs = {}, options = {}) | |
| 51 | + obj = fast_create_without_solr(name, attrs, options) | |
| 52 | + obj.solr_save if options[:search] | |
| 53 | + obj | |
| 54 | + end | |
| 55 | + alias_method_chain :fast_create, :solr | |
| 56 | +end | |
| 57 | + | |
| 58 | +# disable solr actions by default | |
| 59 | +TestSolr.disable | ... | ... |
test/test_solr_helper.rb
| ... | ... | @@ -1,50 +0,0 @@ |
| 1 | -class ActsAsSolr::Post | |
| 2 | - class << self | |
| 3 | - alias_method :execute_orig, :execute | |
| 4 | - end | |
| 5 | -end | |
| 6 | -module ActsAsSolr::ParserMethods | |
| 7 | - alias_method :parse_results_orig, :parse_results | |
| 8 | -end | |
| 9 | - | |
| 10 | -class TestSolr | |
| 11 | - | |
| 12 | - def self.enable | |
| 13 | - ActsAsSolr::Post.class_eval do | |
| 14 | - def self.execute(*args) | |
| 15 | - execute_orig *args | |
| 16 | - end | |
| 17 | - end | |
| 18 | - ActsAsSolr::ParserMethods.module_eval do | |
| 19 | - def parse_results(*args) | |
| 20 | - parse_results_orig *args | |
| 21 | - end | |
| 22 | - end | |
| 23 | - | |
| 24 | - # clear index | |
| 25 | - ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) | |
| 26 | - | |
| 27 | - @solr_disabled = false | |
| 28 | - end | |
| 29 | - | |
| 30 | - def self.disable | |
| 31 | - return if @solr_disabled | |
| 32 | - | |
| 33 | - ActsAsSolr::Post.class_eval do | |
| 34 | - def self.execute(*args) | |
| 35 | - true | |
| 36 | - end | |
| 37 | - end | |
| 38 | - ActsAsSolr::ParserMethods.module_eval do | |
| 39 | - def parse_results(*args) | |
| 40 | - parse_results_orig nil, args[1] | |
| 41 | - end | |
| 42 | - end | |
| 43 | - | |
| 44 | - @solr_disabled = true | |
| 45 | - end | |
| 46 | - | |
| 47 | -end | |
| 48 | - | |
| 49 | -# disable solr actions by default | |
| 50 | -TestSolr.disable |