spree_solr_search 0.30.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ solr
2
+ log/*.log
3
+ tmp/pids/*
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ Solr Search
2
+ ===========
3
+
4
+ ### Installation
5
+
6
+ 1. Add `gem "spree_solr_search"` to your Gemfile
7
+ 1. Run `bundle install`
8
+ 1. Run `rails g spree_solr_search:install`
9
+
10
+ **NOTE:** Master branch works only with Spree 0.30.x.
11
+ If you want use this extension with Spree 0.10.x or 0.11.x, then you should use spree-0-11-stable branch
12
+
13
+ ### Usage
14
+
15
+ To perform the indexing:
16
+
17
+ rake solr:reindex BATCH=500
18
+
19
+
20
+ To start Solr demo-server:
21
+
22
+ rake solr:start SOLR_PATH="/home/roman/www/jetty-solr"
23
+
24
+ To stop Solr demo-server:
25
+
26
+ rake solr:stop
27
+
28
+ To configure production Solr server:
29
+
30
+ edit RAILS_ROOT/config/solr.yml
31
+
32
+ P.S. For development recommended use [jetty-solr](http://github.com/dcrec1/jetty-solr) server.
33
+
34
+
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'jeweler'
5
+ rescue LoadError
6
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
7
+ exit 1
8
+ end
9
+ #gem 'rdoc', '= 2.2'
10
+ #require 'rdoc'
11
+ require 'rake'
12
+ require 'rake/testtask'
13
+ #require 'rake/rdoctask'
14
+ require 'rake/packagetask'
15
+ require 'rake/gempackagetask'
16
+
17
+ Jeweler::Tasks.new do |s|
18
+ s.name = "spree_solr_search"
19
+ s.summary = "Provides search via Apache Solr for a Spree store."
20
+ s.description = s.summary
21
+ s.email = "roman@railsdog.com"
22
+ s.homepage = "http://github.com/romul/spree-solr-search"
23
+ s.authors = ["Roman Smirnov"]
24
+ # s.add_dependency 'spree_core', ['>= 0.30.0.beta1']
25
+ s.add_dependency 'acts_as_solr_reloaded', ['>= 1.4.0']
26
+ s.has_rdoc = false
27
+ #s.extra_rdoc_files = [ "README.rdoc"]
28
+ #s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
29
+ #s.test_files = Dir['test/**/*.{yml,rb}']
30
+ end
31
+ Jeweler::GemcutterTasks.new
32
+
33
+ desc "Default Task"
34
+ task :default => [ :test ]
35
+
36
+ # Run the unit tests
37
+ Rake::TestTask.new { |t|
38
+ t.libs << "test"
39
+ t.pattern = 'test/**/*_test.rb'
40
+ t.warning = true
41
+ }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.30.0.beta1
@@ -0,0 +1,9 @@
1
+ Spree::BaseController.class_eval do
2
+ helper :solr
3
+ before_filter :set_searcher
4
+ RAILS_ROOT = Rails.root.to_s
5
+ private
6
+ def set_searcher
7
+ Spree::Config.searcher = Spree::Search::Solr.new
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module SolrHelper
2
+ def link_to_facet(name, value, count)
3
+ facets_hash = params[:facets]
4
+ facets_hash = {} unless facets_hash.is_a?(Hash)
5
+ facets_hash = facets_hash.merge({name => ["\"#{value}\"", facets_hash[name]].join(',')})
6
+ link_to("#{value} (#{count})", url_for(request.params.merge({:facets => facets_hash})))
7
+ end
8
+ end
@@ -0,0 +1,66 @@
1
+ Product.class_eval do
2
+ acts_as_solr :fields => [:name, :description, :is_active, {:price => :float},
3
+ :taxon_ids, :price_range, :taxon_names,
4
+ :brand_property, :color_option, :size_option],
5
+ :facets=>[:price_range, :taxon_names,
6
+ :brand_property, :color_option, :size_option]
7
+
8
+ def taxon_ids
9
+ taxons.map(&:id)
10
+ end
11
+
12
+ def is_active
13
+ !deleted_at &&
14
+ (available_on <= Time.zone.now) &&
15
+ (Spree::Config[:allow_backorders] || count_on_hand > 0)
16
+ end
17
+
18
+ private
19
+
20
+ def taxon_names
21
+ taxons.map(&:name)
22
+ end
23
+
24
+ def price_range
25
+ price_ranges = YAML.load(Spree::Config[:product_price_ranges])
26
+ case price
27
+ when 0..25
28
+ price_ranges[0]
29
+ when 25..50
30
+ price_ranges[1]
31
+ when 50..100
32
+ price_ranges[2]
33
+ when 100..200
34
+ price_ranges[3]
35
+ else
36
+ price_ranges[4]
37
+ end
38
+ end
39
+
40
+ def brand_property
41
+ pp = ProductProperty.first(:joins => :property,
42
+ :conditions => {:product_id => self.id, :properties => {:name => 'brand'}})
43
+ pp ? pp.value : ''
44
+ end
45
+
46
+ def color_option
47
+ get_option_values('color')
48
+ end
49
+
50
+ def size_option
51
+ get_option_values('size')
52
+ end
53
+
54
+ def get_option_values(option_name)
55
+ sql = <<-eos
56
+ SELECT DISTINCT ov.id, ov.presentation
57
+ FROM option_values AS ov
58
+ LEFT JOIN option_types AS ot ON (ov.option_type_id = ot.id)
59
+ LEFT JOIN option_values_variants AS ovv ON (ovv.option_value_id = ov.id)
60
+ LEFT JOIN variants AS v ON (ovv.variant_id = v.id)
61
+ LEFT JOIN products AS p ON (v.product_id = p.id)
62
+ WHERE (ot.name = '#{option_name}' AND p.id = #{self.id});
63
+ eos
64
+ OptionValue.find_by_sql(sql).map(&:presentation)
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ <%
2
+ facets = Spree::Config.searcher.facets || []
3
+ taxon_names = @taxon ? @taxon.self_and_descendants.map(&:name) : []
4
+ for facet in facets
5
+ options = facet.options
6
+ options = options.sort{|x,y| y.count <=> x.count} unless facet.name == "price_range"
7
+ unless options.empty? %>
8
+ <h4><%= t "#{facet.name}_facet" %></h4>
9
+ <ul><%
10
+ for option in options %>
11
+ <li>
12
+ <%= link_to_facet(facet.name, option.name, option.count) %>
13
+ </li><%
14
+ end %>
15
+ </ul><%
16
+ end
17
+ end
18
+ %>
@@ -0,0 +1,6 @@
1
+ <% if suggestion = Spree::Config.searcher.suggest %>
2
+ <p>
3
+ <%= t(:did_you_mean, :default => "Did you mean") %>
4
+ <%= link_to h(suggestion), url_for(request.params.merge({:keywords => suggestion})) %>?
5
+ </p>
6
+ <% end %>
@@ -0,0 +1,6 @@
1
+ en:
2
+ taxon_names_facet: "Taxon"
3
+ price_range_facet: "Price"
4
+ brand_property_facet: "Brand"
5
+ color_option_facet: "Color"
6
+ size_option_facet: "Size"
@@ -0,0 +1,6 @@
1
+ ru-RU:
2
+ taxon_names_facet: "Категория"
3
+ price_range_facet: "Цена"
4
+ brand_property_facet: "Бренд"
5
+ color_option_facet: "Цвет"
6
+ size_option_facet: "Размер"
@@ -0,0 +1,6 @@
1
+ ru:
2
+ taxon_names_facet: "Категория"
3
+ price_range_facet: "Цена"
4
+ brand_property_facet: "Бренд"
5
+ color_option_facet: "Цвет"
6
+ size_option_facet: "Размер"
@@ -0,0 +1,17 @@
1
+ module SpreeSolrSearch
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../templates", __FILE__)
5
+
6
+ desc "Configures your Rails application for use with spree_solr_search."
7
+
8
+ def copy_config
9
+ template "solr.yml", "config/solr.yml"
10
+ end
11
+
12
+ # def show_readme
13
+ # readme "README" if behavior == :invoke
14
+ # end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # Config file for the acts_as_solr plugin.
2
+ #
3
+ # If you change the host or port number here, make sure you update
4
+ # them in your Solr config file
5
+
6
+ development:
7
+ url: http://127.0.0.1:8982/solr
8
+
9
+ production:
10
+ url: http://127.0.0.1:8983/solr
11
+ jvm_options: -server -d64 -Xmx1024M -Xms64M
12
+
13
+ test:
14
+ url: http://127.0.0.1:8981/solr
15
+
@@ -0,0 +1,19 @@
1
+ # By Henrik Nyh <http://henrik.nyh.se> 2007-06-15.
2
+ # Free to modify and redistribute with credit.
3
+
4
+ # Adds a find_all_by_solr method to acts_as_solr models to enable
5
+ # will_paginate for acts_as_solr search results.
6
+
7
+ module ActsAsSolr
8
+ module PaginationExtension
9
+
10
+ def find_all_by_solr(query, options)
11
+ Spree::Config.searcher.products.slice(options[:offset], options[:limit])
12
+ end
13
+
14
+ end
15
+ end
16
+
17
+ module ActsAsSolr::ClassMethods
18
+ include ActsAsSolr::PaginationExtension
19
+ end
@@ -0,0 +1,92 @@
1
+ module Spree::Search
2
+ class Solr < Spree::Search::Base
3
+ # method should return hash with conditions {:conditions=> "..."} for Product model
4
+ def get_products_conditions_for(query)
5
+ facets = {
6
+ :fields => [:price_range, :taxon_names, :brand_property, :color_option, :size_option],
7
+ :browse => @properties[:facets_hash].map{|k,v| "#{k}:#{v}"},
8
+ :zeros => false
9
+ }
10
+ search_options = {:facets => facets, :limit => 25000, :lazy => true}
11
+ if order_by_price
12
+ search_options.merge!(:order => (order_by_price == 'descend') ? "price desc" : "price asc")
13
+ end
14
+ full_query = query + " AND is_active:(true)"
15
+ if taxon
16
+ taxons_query = taxon.self_and_descendants.map{|t| "taxon_ids:(#{t.id})"}.join(" OR ")
17
+ full_query += " AND (#{taxons_query})"
18
+ end
19
+
20
+ result = Product.find_by_solr(full_query, search_options)
21
+ @properties[:products] = result.records
22
+ count = result.records.size
23
+
24
+ products = Product.paginate(query, :finder => 'find_all_by_solr',
25
+ :page => page, :per_page => per_page, :total_entries => count)
26
+
27
+ @properties[:products] = products
28
+ @properties[:suggest] = nil
29
+ begin
30
+ if suggest = result.suggest
31
+ suggest.sub!(/\sAND.*/, '')
32
+ @properties[:suggest] = suggest if suggest != query
33
+ end
34
+ rescue
35
+ end
36
+
37
+ @properties[:facets] = parse_facets_hash(result.facets)
38
+ {:conditions=> ["products.id IN (?)", products.map(&:id)]}
39
+ end
40
+
41
+ def prepare(params)
42
+ @properties[:facets_hash] = params[:facets] || {}
43
+ @properties[:taxon] = params[:taxon].blank? ? nil : Taxon.find(params[:taxon])
44
+ @properties[:per_page] = params[:per_page]
45
+ @properties[:page] = params[:page]
46
+ @properties[:manage_pagination] = true
47
+ @properties[:order_by_price] = params[:order_by_price]
48
+ end
49
+
50
+ private
51
+
52
+ def parse_facets_hash(facets_hash = {"facet_fields" => {}})
53
+ facets = []
54
+ price_ranges = YAML::load(Spree::Config[:product_price_ranges])
55
+ facets_hash["facet_fields"].each do |name, options|
56
+ next if options.size <= 1
57
+ facet = Facet.new(name.sub('_facet', ''))
58
+ if name == 'price_range_facet'
59
+ price_ranges.each do |price_range|
60
+ count = options[price_range]
61
+ facet.options << FacetOption.new(price_range, count) if count
62
+ end
63
+ else
64
+ options.each do |value, count|
65
+ facet.options << FacetOption.new(value, count)
66
+ end
67
+ end
68
+ facets << facet
69
+ end
70
+ facets
71
+ end
72
+ end
73
+
74
+
75
+ class Facet
76
+ attr_accessor :options
77
+ attr_accessor :name
78
+ def initialize(name, options = [])
79
+ self.name = name
80
+ self.options = options
81
+ end
82
+ end
83
+
84
+ class FacetOption
85
+ attr_accessor :name
86
+ attr_accessor :count
87
+ def initialize(name, count)
88
+ self.name = name
89
+ self.count = count
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,21 @@
1
+ require 'spree_core'
2
+ require 'spree_solr_search_hooks'
3
+
4
+ module SpreeSolrSearch
5
+ class Engine < Rails::Engine
6
+ def self.activate
7
+ require 'acts_as_solr'
8
+ require 'solr_pagination'
9
+ ENV['RAILS_ENV'] = Rails.env
10
+
11
+ Spree::Config.set(:product_price_ranges =>
12
+ ["Under $25", "$25 to $50", "$50 to $100", "$100 to $200", "$200 and above"])
13
+
14
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
15
+ Rails.env == "production" ? require(c) : load(c)
16
+ end
17
+ end
18
+ config.to_prepare &method(:activate).to_proc
19
+ config.autoload_paths += %W(#{config.root}/lib)
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ class SpreeSolrSearchHooks < Spree::ThemeSupport::HookListener
2
+
3
+ insert_before :search_results, 'products/facets'
4
+ insert_before :search_results, 'products/suggestion'
5
+
6
+ end
@@ -0,0 +1,10 @@
1
+ begin
2
+ ENV['ONLY'] = "Product"
3
+ SOLR_PATH = ENV['SOLR_PATH']
4
+ RAILS_DEFAULT_LOGGER = Logger.new(Rails.root.join("log", Rails.env + ".log"))
5
+ RAILS_ROOT = Rails.root.to_s
6
+ require 'acts_as_solr_reloaded'
7
+ load 'tasks/solr.rake'
8
+ rescue LoadError
9
+ puts "WARNING: acts_as_solr_reloaded gem appears to be unavailable. Please install with bundle install."
10
+ end
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{spree_solr_search}
8
+ s.version = "0.30.0.beta1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Roman Smirnov"]
12
+ s.date = %q{2010-08-26}
13
+ s.description = %q{Provides search via Apache Solr for a Spree store.}
14
+ s.email = %q{roman@railsdog.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.md",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "app/controllers/spree/base_controller_decorator.rb",
24
+ "app/helpers/solr_helper.rb",
25
+ "app/models/product_decorator.rb",
26
+ "app/views/products/_facets.html.erb",
27
+ "app/views/products/_suggestion.html.erb",
28
+ "config/locales/en.yml",
29
+ "config/locales/ru-RU.yml",
30
+ "config/locales/ru.yml",
31
+ "lib/generators/spree_solr_search/install_generator.rb",
32
+ "lib/generators/templates/solr.yml",
33
+ "lib/solr_pagination.rb",
34
+ "lib/spree/search/solr.rb",
35
+ "lib/spree_solr_search.rb",
36
+ "lib/spree_solr_search_hooks.rb",
37
+ "lib/tasks/acts_as_solr.rake",
38
+ "spree_solr_search.gemspec"
39
+ ]
40
+ s.homepage = %q{http://github.com/romul/spree-solr-search}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.6}
44
+ s.summary = %q{Provides search via Apache Solr for a Spree store.}
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<acts_as_solr_reloaded>, [">= 1.4.0"])
52
+ else
53
+ s.add_dependency(%q<acts_as_solr_reloaded>, [">= 1.4.0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<acts_as_solr_reloaded>, [">= 1.4.0"])
57
+ end
58
+ end
59
+
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_solr_search
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: true
5
+ segments:
6
+ - 0
7
+ - 30
8
+ - 0
9
+ - beta1
10
+ version: 0.30.0.beta1
11
+ platform: ruby
12
+ authors:
13
+ - Roman Smirnov
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-26 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: acts_as_solr_reloaded
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 4
31
+ - 0
32
+ version: 1.4.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Provides search via Apache Solr for a Spree store.
36
+ email: roman@railsdog.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.md
43
+ files:
44
+ - .gitignore
45
+ - README.md
46
+ - Rakefile
47
+ - VERSION
48
+ - app/controllers/spree/base_controller_decorator.rb
49
+ - app/helpers/solr_helper.rb
50
+ - app/models/product_decorator.rb
51
+ - app/views/products/_facets.html.erb
52
+ - app/views/products/_suggestion.html.erb
53
+ - config/locales/en.yml
54
+ - config/locales/ru-RU.yml
55
+ - config/locales/ru.yml
56
+ - lib/generators/spree_solr_search/install_generator.rb
57
+ - lib/generators/templates/solr.yml
58
+ - lib/solr_pagination.rb
59
+ - lib/spree/search/solr.rb
60
+ - lib/spree_solr_search.rb
61
+ - lib/spree_solr_search_hooks.rb
62
+ - lib/tasks/acts_as_solr.rake
63
+ - spree_solr_search.gemspec
64
+ has_rdoc: true
65
+ homepage: http://github.com/romul/spree-solr-search
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --charset=UTF-8
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">"
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 1
86
+ - 3
87
+ - 1
88
+ version: 1.3.1
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.6
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Provides search via Apache Solr for a Spree store.
96
+ test_files: []
97
+