Commit 7eb7d4bf799ffde3f9e370f961701a2f1e3471e3
Committed by
Rodrigo Souto
1 parent
a3c2ad9b
Exists in
staging
and in
42 other branches
solr_plugin: Convert scopes to solr filters
Showing
7 changed files
with
141 additions
and
9 deletions
Show diff stats
app/controllers/application_controller.rb
| ... | ... | @@ -174,8 +174,6 @@ class ApplicationController < ActionController::Base |
| 174 | 174 | end |
| 175 | 175 | |
| 176 | 176 | def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) |
| 177 | - scope = scope.send(options[:filter]) if options[:filter] | |
| 178 | - | |
| 179 | 177 | @plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || |
| 180 | 178 | fallback_find_by_contents(asset, scope, query, paginate_options, options) |
| 181 | 179 | end | ... | ... |
app/controllers/public/search_controller.rb
| ... | ... | @@ -214,6 +214,13 @@ class SearchController < PublicController |
| 214 | 214 | @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter}) |
| 215 | 215 | end |
| 216 | 216 | |
| 217 | + def find_by_contents asset, scope, query, paginate_options={:page => 1}, options={} | |
| 218 | + # only apply fitlers to empty query, sorting is engine specific | |
| 219 | + scope = scope.send(options[:filter]) if options[:filter] and @empty_query | |
| 220 | + | |
| 221 | + super asset, scope, query, paginate_options, options | |
| 222 | + end | |
| 223 | + | |
| 217 | 224 | private |
| 218 | 225 | |
| 219 | 226 | def visible_profiles(klass, *extra_relations) | ... | ... |
plugins/solr/lib/ext/article.rb
| ... | ... | @@ -24,7 +24,8 @@ class Article |
| 24 | 24 | {:slug => :text}, {:body => :text}, |
| 25 | 25 | {:abstract => :text}, {:filename => :text}, |
| 26 | 26 | # filtered fields |
| 27 | - {:solr_plugin_public => :boolean}, {:environment_id => :integer}, | |
| 27 | + {:solr_plugin_public => :boolean}, {:published => :boolean}, | |
| 28 | + {:environment_id => :integer}, | |
| 28 | 29 | {:profile_id => :integer}, :language, |
| 29 | 30 | {:solr_plugin_category_filter => :integer}, |
| 30 | 31 | # ordered/query-boosted fields | ... | ... |
plugins/solr/lib/ext/profile.rb
| ... | ... | @@ -28,7 +28,7 @@ class Profile |
| 28 | 28 | {:solr_plugin_category_filter => :integer}, |
| 29 | 29 | # ordered/query-boosted fields |
| 30 | 30 | {:solr_plugin_name_sortable => :string}, {:user_id => :integer}, |
| 31 | - :enabled, :active, :validated, :public_profile, | |
| 31 | + :enabled, :active, :validated, :public_profile, :visible, | |
| 32 | 32 | {:lat => :float}, {:lng => :float}, |
| 33 | 33 | :updated_at, :created_at, |
| 34 | 34 | ], | ... | ... |
plugins/solr/lib/solr_plugin.rb
| ... | ... | @@ -18,16 +18,69 @@ class SolrPlugin < Noosfero::Plugin |
| 18 | 18 | true |
| 19 | 19 | end |
| 20 | 20 | |
| 21 | + def solr_search? empty_query, klass | |
| 22 | + not empty_query or klass == Product | |
| 23 | + end | |
| 24 | + | |
| 21 | 25 | def find_by_contents(asset, scope, query, paginate_options={}, options={}) |
| 22 | 26 | klass = asset_class(asset) |
| 23 | - category = options.delete(:category) | |
| 24 | - filter = options.delete(:filter) | |
| 27 | + category = options[:category] | |
| 28 | + empty_query = empty_query? query, category | |
| 25 | 29 | |
| 26 | - return if empty_query?(query, category) && klass != Product | |
| 30 | + return unless solr_search? empty_query, klass | |
| 27 | 31 | |
| 28 | 32 | solr_options = solr_options(class_asset(klass), category) |
| 29 | - solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) | |
| 30 | - klass.find_by_contents(query, paginate_options, solr_options.merge(options)) | |
| 33 | + solr_options[:filter_queries] ||= [] | |
| 34 | + solr_options[:filter_queries] += scopes_to_solr_filters scope, klass, options | |
| 35 | + solr_options.merge! products_options(user) if klass == Product and empty_query | |
| 36 | + solr_options.merge! options.except(:category, :filter) | |
| 37 | + | |
| 38 | + scope.find_by_contents query, paginate_options, solr_options | |
| 39 | + end | |
| 40 | + | |
| 41 | + protected | |
| 42 | + | |
| 43 | + def scopes_to_solr_filters scope, klass = nil, options = {} | |
| 44 | + filter_queries = [] | |
| 45 | + klass ||= scope.base_class | |
| 46 | + solr_fields = klass.configuration[:solr_fields].keys | |
| 47 | + scopes_applied = scope.scopes_applied.dup rescue [] #rescue association and class direct filtering | |
| 48 | + | |
| 49 | + scope.current_scoped_methods[:create].each do |attr, value| | |
| 50 | + next unless solr_fields.include? attr.to_sym | |
| 51 | + | |
| 52 | + # if the filter is present here, then prefer it | |
| 53 | + scopes_applied.reject!{ |name| name == attr.to_sym } | |
| 54 | + | |
| 55 | + filter_queries << "#{attr}:#{value}" | |
| 56 | + end | |
| 57 | + | |
| 58 | + scopes_applied.each do |name| | |
| 59 | + next if name.to_s == options[:filter].to_s | |
| 60 | + | |
| 61 | + has_value = name === Hash | |
| 62 | + if has_value | |
| 63 | + name, args = name.keys.first, name.values.first | |
| 64 | + value = args.first | |
| 65 | + end | |
| 66 | + | |
| 67 | + related_field = nil | |
| 68 | + related_field = name if solr_fields.include? name | |
| 69 | + related_field = "solr_plugin_#{name}" if solr_fields.include? :"solr_plugin_#{name}" | |
| 70 | + | |
| 71 | + if has_value | |
| 72 | + if related_field | |
| 73 | + filter_queries << "#{related_field}:#{value}" | |
| 74 | + else | |
| 75 | + filter_queries << klass.send("solr_filter_#{name}", *args) | |
| 76 | + end | |
| 77 | + else | |
| 78 | + raise "Undeclared solr field for scope #{name}" if related_field.nil? | |
| 79 | + filter_queries << "#{related_field}:true" | |
| 80 | + end | |
| 81 | + end | |
| 82 | + | |
| 83 | + filter_queries | |
| 31 | 84 | end |
| 32 | 85 | |
| 33 | 86 | def method_missing method, *args, &block | ... | ... |
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | |
| 2 | + | |
| 3 | +class SolrPlugin::PluginTest < ActiveSupport::TestCase | |
| 4 | + | |
| 5 | + def setup | |
| 6 | + @plugin = SolrPlugin.new | |
| 7 | + end | |
| 8 | + attr_reader :plugin | |
| 9 | + | |
| 10 | + should 'convert scopes to solr filters' do | |
| 11 | + person = create_user('test').person | |
| 12 | + result = plugin.send :scopes_to_solr_filters, person.files.public.published | |
| 13 | + assert_equal result, ["profile_id:#{person.id}", "published:'true'", "solr_plugin_public:true"] | |
| 14 | + end | |
| 15 | + | |
| 16 | +end | ... | ... |
vendor/plugins/monkey_patches/named_scope_with_applied_names/init.rb
0 → 100644
| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | +require_dependency 'active_record/named_scope' | |
| 2 | + | |
| 3 | +if Rails::VERSION::STRING < "2.3.99" | |
| 4 | + | |
| 5 | + module ::ActiveRecord | |
| 6 | + | |
| 7 | + module NamedScope | |
| 8 | + | |
| 9 | + module ClassMethods | |
| 10 | + | |
| 11 | + def named_scope_with_applied_names name, options = {}, &block | |
| 12 | + named_scope_without_applied_names name, options, &block | |
| 13 | + | |
| 14 | + name = name.to_sym | |
| 15 | + scopes[name] = lambda do |parent_scope, *args| | |
| 16 | + scope = Scope.new(parent_scope, case options | |
| 17 | + when Hash | |
| 18 | + options | |
| 19 | + when Proc | |
| 20 | + if self.model_name != parent_scope.model_name | |
| 21 | + options.bind(parent_scope).call(*args) | |
| 22 | + else | |
| 23 | + options.call(*args) | |
| 24 | + end | |
| 25 | + end, &block) | |
| 26 | + scope.scope_name = name | |
| 27 | + scope | |
| 28 | + end | |
| 29 | + end | |
| 30 | + alias_method_chain :named_scope, :applied_names | |
| 31 | + end | |
| 32 | + | |
| 33 | + class Scope | |
| 34 | + attr_accessor :scope_name, :scopes_applied | |
| 35 | + | |
| 36 | + def initialize_with_applied_names proxy_scope, options, &block | |
| 37 | + initialize_without_applied_names proxy_scope, options, &block | |
| 38 | + self.scopes_applied ||= [] | |
| 39 | + self.scopes_applied += proxy_scope.send :scopes_applied if Scope === proxy_scope | |
| 40 | + | |
| 41 | + # unrelated bugfix: use if instead of unless | |
| 42 | + if (Scope === proxy_scope || ActiveRecord::Associations::AssociationCollection === proxy_scope) | |
| 43 | + @current_scoped_methods_when_defined = proxy_scope.send(:current_scoped_methods) | |
| 44 | + end | |
| 45 | + end | |
| 46 | + alias_method_chain :initialize, :applied_names | |
| 47 | + | |
| 48 | + def scope_name= name | |
| 49 | + @scope_name = name | |
| 50 | + self.scopes_applied << @scope_name | |
| 51 | + end | |
| 52 | + | |
| 53 | + end | |
| 54 | + | |
| 55 | + end | |
| 56 | + end | |
| 57 | +end | ... | ... |