From cde8c79b8879af54d2d2fb61b872b640317c812f Mon Sep 17 00:00:00 2001 From: steve Date: Sat, 31 Jan 2009 10:07:21 -0500 Subject: [PATCH] lovd now runs shpinx --- .gitignore | 3 +- README | 15 +- app/controllers/admin/users_controller.rb | 2 +- app/controllers/profiles_controller.rb | 2 +- app/models/profile.rb | 7 - test/functional/profiles_controller_test.rb | 4 +- test/integration/spider_test.rb | 2 +- .../lib/thinking_sphinx/index/builder.rb | 224 ++++++++++++++++++ .../lib/thinking_sphinx/index/faux_column.rb | 110 +++++++++ 9 files changed, 345 insertions(+), 24 deletions(-) create mode 100644 vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/builder.rb create mode 100644 vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/faux_column.rb diff --git a/.gitignore b/.gitignore index 8fc03c9..cf2883f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,7 @@ log/*.pid tmp config/database.yml config/*.sphinx.conf -index public/system public/javascripts/less_routes.js test/public/system -vendor/rails \ No newline at end of file +vendor/rails diff --git a/README b/README index ed2f59b..9d9fcb1 100644 --- a/README +++ b/README @@ -28,7 +28,7 @@ Quick Setup (currently for non-Windows users only - due to ferret gem issues): 1. Edit config/database.yml.tmp to reflect the database names you would like to use. 2. Edit config/environments/production.rb so asset_host reflects the name of the production asset server 3. cp config/database.yml.tmp config/database.yml - 4. MAKE SURE YOU UPGRADE TO GEMS 1.2. + 4. MAKE SURE YOU UPGRADE TO GEMS 1.3. 5. RUN gem sources -a http://gems.github.com 6. rake lovdbyless:getting_started 7. rake test @@ -51,11 +51,6 @@ Install the Required Gems: TIPS: -Installing ferret on Windows -1. Running gem install ferret does not work. Instead, download the gem directly from http://rubyforge.org/frs/?group_id=1028 -2. Download file: ferret-0.11.6-mswin32.gem -3. From the directory you downloaded the gem to: gem install ferret-0.11.6-mswin32.gem - Installing ImageMagick and RMagick See these posts for tips: http://b.lesseverything.com/2007/9/26/installing-imagemagick-and-rmagick-on-mac-os-x @@ -84,11 +79,11 @@ Setup default values: 12. Edit application.css to suite your tastes. 13. Edit app/views/home/terms. -Configure Ferret: +Configure Thinking Sphinx: -14. Feel free to replace ferret with the search engine of your choice. -15. Acts_s_ferret home page: http://projects.jkraemer.net/acts_as_ferret/wiki. -16. We recommend using the drb server as described here: http://projects.jkraemer.net/acts_as_ferret/wiki/DrbServer. +14. rake ts:start +15. rake ts:in +16. Rake ts:start again in sphinx is not running. Start Lovd By Less: diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 545ee0d..6b0544a 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -36,6 +36,6 @@ def search_results else p = [] end - @results = Profile.search_results((p.delete(:q) || ''), :page => @page, :per_page => @per_page) + @results = Profile.search(p.delete(:q) || '') end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 9a3a7db..a5020ba 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -120,6 +120,6 @@ def search_results else p = [] end - @results = Profile.search_results((p.delete(:q) || ''), :page => @page, :per_page => @per_page) + @results = Profile.search(p.delete(:q) || '') end end diff --git a/app/models/profile.rb b/app/models/profile.rb index b7371fa..05db1e9 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -188,13 +188,6 @@ def can_send_messages - def self.search_results query = '', options = {} - arr = self.search(query) - logger.debug arr.inspect - arr - end - - protected def fix_http str diff --git a/test/functional/profiles_controller_test.rb b/test/functional/profiles_controller_test.rb index 3fba676..4675f68 100644 --- a/test/functional/profiles_controller_test.rb +++ b/test/functional/profiles_controller_test.rb @@ -4,7 +4,7 @@ class ProfilesControllerTest < ActionController::TestCase context 'on POST to :search' do setup do - Profile.stubs(:search_results).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) + Profile.stubs(:search).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) post :search, {:q => 'user'} end @@ -15,7 +15,7 @@ class ProfilesControllerTest < ActionController::TestCase context 'on GET to :index' do setup do - Profile.stubs(:search_results).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) + Profile.stubs(:search).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) get :index end diff --git a/test/integration/spider_test.rb b/test/integration/spider_test.rb index d0c0903..2073963 100644 --- a/test/integration/spider_test.rb +++ b/test/integration/spider_test.rb @@ -32,7 +32,7 @@ def test_spider_user def test_spider_admin - Profile.stubs(:search_results).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) + Profile.stubs(:search).returns(ThinkingSphinx::Collection.new(1, 1, 1, 1)) puts '' puts 'test_spider_admin' get "/login" diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/builder.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/builder.rb new file mode 100644 index 0000000..918c1d0 --- /dev/null +++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/builder.rb @@ -0,0 +1,224 @@ +module ThinkingSphinx + class Index + # The Builder class is the core for the index definition block processing. + # There are four methods you really need to pay attention to: + # - indexes (aliased to includes and attribute) + # - has (aliased to attribute) + # - where + # - set_property (aliased to set_properties) + # + # The first two of these methods allow you to define what data makes up + # your indexes. #where provides a method to add manual SQL conditions, and + # set_property allows you to set some settings on a per-index basis. Check + # out each method's documentation for better ideas of usage. + # + class Builder + class << self + # No idea where this is coming from - haven't found it in any ruby or + # rails documentation. It's not needed though, so it gets undef'd. + # Hopefully the list of methods that get in the way doesn't get too + # long. + HiddenMethods = [:parent, :name, :id, :type].each { |method| + define_method(method) { + caller.grep(/irb.completion/).empty? ? method_missing(method) : super + } + } + + attr_accessor :fields, :attributes, :properties, :conditions, + :groupings + + # Set up all the collections. Consider this the equivalent of an + # instance's initialize method. + # + def setup + @fields = [] + @attributes = [] + @properties = {} + @conditions = [] + @groupings = [] + end + + # This is how you add fields - the strings Sphinx looks at - to your + # index. Technically, to use this method, you need to pass in some + # columns and options - but there's some neat method_missing stuff + # happening, so lets stick to the expected syntax within a define_index + # block. + # + # Expected options are :as, which points to a column alias in symbol + # form, and :sortable, which indicates whether you want to sort by this + # field. + # + # Adding Single-Column Fields: + # + # You can use symbols or methods - and can chain methods together to + # get access down the associations tree. + # + # indexes :id, :as => :my_id + # indexes :name, :sortable => true + # indexes first_name, last_name, :sortable => true + # indexes users.posts.content, :as => :post_content + # indexes users(:id), :as => :user_ids + # + # Keep in mind that if any keywords for Ruby methods - such as id or + # name - clash with your column names, you need to use the symbol + # version (see the first, second and last examples above). + # + # If you specify multiple columns (example #2), a field will be created + # for each. Don't use the :as option in this case. If you want to merge + # those columns together, continue reading. + # + # Adding Multi-Column Fields: + # + # indexes [first_name, last_name], :as => :name + # indexes [location, parent.location], :as => :location + # + # To combine multiple columns into a single field, you need to wrap + # them in an Array, as shown by the above examples. There's no + # limitations on whether they're symbols or methods or what level of + # associations they come from. + # + # Adding SQL Fragment Fields + # + # You can also define a field using an SQL fragment, useful for when + # you would like to index a calculated value. + # + # indexes "age < 18", :as => :minor + # + def indexes(*args) + options = args.extract_options! + args.each do |columns| + fields << Field.new(FauxColumn.coerce(columns), options) + + if fields.last.sortable + attributes << Attribute.new( + fields.last.columns.collect { |col| col.clone }, + options.merge( + :type => :string, + :as => fields.last.unique_name.to_s.concat("_sort").to_sym + ) + ) + end + end + end + alias_method :field, :indexes + alias_method :includes, :indexes + + # This is the method to add attributes to your index (hence why it is + # aliased as 'attribute'). The syntax is the same as #indexes, so use + # that as starting point, but keep in mind the following points. + # + # An attribute can have an alias (the :as option), but it is always + # sortable - so you don't need to explicitly request that. You _can_ + # specify the data type of the attribute (the :type option), but the + # code's pretty good at figuring that out itself from peering into the + # database. + # + # Attributes are limited to the following types: integers, floats, + # datetimes (converted to timestamps), booleans and strings. Don't + # forget that Sphinx converts string attributes to integers, which are + # useful for sorting, but that's about it. + # + # You can also have a collection of integers for multi-value attributes + # (MVAs). Generally these would be through a has_many relationship, + # like in this example: + # + # has posts(:id), :as => :post_ids + # + # This allows you to filter on any of the values tied to a specific + # record. Might be best to read through the Sphinx documentation to get + # a better idea of that though. + # + # Adding SQL Fragment Attributes + # + # You can also define an attribute using an SQL fragment, useful for + # when you would like to index a calculated value. Don't forget to set + # the type of the attribute though: + # + # has "age < 18", :as => :minor, :type => :boolean + # + # If you're creating attributes for latitude and longitude, don't + # forget that Sphinx expects these values to be in radians. + # + def has(*args) + options = args.extract_options! + args.each do |columns| + attributes << Attribute.new(FauxColumn.coerce(columns), options) + end + end + alias_method :attribute, :has + + # Use this method to add some manual SQL conditions for your index + # request. You can pass in as many strings as you like, they'll get + # joined together with ANDs later on. + # + # where "user_id = 10" + # where "parent_type = 'Article'", "created_at < NOW()" + # + def where(*args) + @conditions += args + end + + # Use this method to add some manual SQL strings to the GROUP BY + # clause. You can pass in as many strings as you'd like, they'll get + # joined together with commas later on. + # + # group_by "lat", "lng" + # + def group_by(*args) + @groupings += args + end + + # This is what to use to set properties on the index. Chief amongst + # those is the delta property - to allow automatic updates to your + # indexes as new models are added and edited - but also you can + # define search-related properties which will be the defaults for all + # searches on the model. + # + # set_property :delta => true + # set_property :field_weights => {"name" => 100} + # set_property :order => "name ASC" + # set_property :include => :picture + # set_property :select => 'name' + # + # Also, the following two properties are particularly relevant for + # geo-location searching - latitude_attr and longitude_attr. If your + # attributes for these two values are named something other than + # lat/latitude or lon/long/longitude, you can dictate what they are + # when defining the index, so you don't need to specify them for every + # geo-related search. + # + # set_property :latitude_attr => "lt", :longitude_attr => "lg" + # + # Please don't forget to add a boolean field named 'delta' to your + # model's database table if enabling the delta index for it. + # + def set_property(*args) + options = args.extract_options! + if options.empty? + @properties[args[0]] = args[1] + else + @properties.merge!(options) + end + end + alias_method :set_properties, :set_property + + # Handles the generation of new columns for the field and attribute + # definitions. + # + def method_missing(method, *args) + FauxColumn.new(method, *args) + end + + # A method to allow adding fields from associations which have names + # that clash with method names in the Builder class (ie: properties, + # fields, attributes). + # + # Example: indexes assoc(:properties).column + # + def assoc(assoc) + FauxColumn.new(method) + end + end + end + end +end diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/faux_column.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/faux_column.rb new file mode 100644 index 0000000..84068de --- /dev/null +++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/index/faux_column.rb @@ -0,0 +1,110 @@ +module ThinkingSphinx + class Index + # Instances of this class represent database columns and the stack of + # associations that lead from the base model to them. + # + # The name and stack are accessible through methods starting with __ to + # avoid conflicting with the method_missing calls that build the stack. + # + class FauxColumn + # Create a new column with a pre-defined stack. The top element in the + # stack will get shifted to be the name value. + # + def initialize(*stack) + @name = stack.pop + @stack = stack + end + + def self.coerce(columns) + case columns + when Symbol, String + FauxColumn.new(columns) + when Array + columns.collect { |col| FauxColumn.coerce(col) } + when FauxColumn + columns + else + nil + end + end + + # Can't use normal method name, as that could be an association or + # column name. + # + def __name + @name + end + + # Can't use normal method name, as that could be an association or + # column name. + # + def __stack + @stack + end + + # Returns true if the stack is empty *and* if the name is a string - + # which is an indication that of raw SQL, as opposed to a value from a + # table's column. + # + def is_string? + @name.is_a?(String) && @stack.empty? + end + + # This handles any 'invalid' method calls and sets them as the name, + # and pushing the previous name into the stack. The object returns + # itself. + # + # If there's a single argument, it becomes the name, and the method + # symbol goes into the stack as well. Multiple arguments means new + # columns with the original stack and new names (from each argument) gets + # returned. + # + # Easier to explain with examples: + # + # col = FauxColumn.new :a, :b, :c + # col.__name #=> :c + # col.__stack #=> [:a, :b] + # + # col.whatever #=> col + # col.__name #=> :whatever + # col.__stack #=> [:a, :b, :c] + # + # col.something(:id) #=> col + # col.__name #=> :id + # col.__stack #=> [:a, :b, :c, :whatever, :something] + # + # cols = col.short(:x, :y, :z) + # cols[0].__name #=> :x + # cols[0].__stack #=> [:a, :b, :c, :whatever, :something, :short] + # cols[1].__name #=> :y + # cols[1].__stack #=> [:a, :b, :c, :whatever, :something, :short] + # cols[2].__name #=> :z + # cols[2].__stack #=> [:a, :b, :c, :whatever, :something, :short] + # + # Also, this allows method chaining to build up a relevant stack: + # + # col = FauxColumn.new :a, :b + # col.__name #=> :b + # col.__stack #=> [:a] + # + # col.one.two.three #=> col + # col.__name #=> :three + # col.__stack #=> [:a, :b, :one, :two] + # + def method_missing(method, *args) + @stack << @name + @name = method + + if (args.empty?) + self + elsif (args.length == 1) + method_missing(args.first) + else + args.collect { |arg| + FauxColumn.new(@stack + [@name, arg]) + } + end + end + end + end +end \ No newline at end of file