Need help with multi_search

I have been trying to use multi_search to search accross multiple
associated models, but I have had no luck at all. I have scoured the net
and this forum for all similar posts, but none of them contain enough
code for me to get it to work.

I am successfully able to search individual models, and then display the
results without a problem.

I have the following 2 models, Product and Component. The Product model
has_many Components, and the Component model belongs_to Product.

Could anyone provide an example of how they would search the Product
model for a query term, which will then return not only the Products
that match the query, but the Components (related to the Products) as
well.

I would really appreciate a “back-to-basics” example, as I think I have
confused myself completely in my attempts.

Thanks.

Graham,

First, to do multi_search make sure to declare :store_class_name => true
in both the Product and Component files in order to do multi_search.

class Product < ActiveRecord::Base
acts_as_ferret :store_class_name => true

end

class Component < ActiveRecord::Base
acts_as_ferret :store_class_name => true

end

Next, if you want to retrieve products based on in its components, you
have to index your product based on the appropriate component values:

class Product < ActiveRecord::Base
acts_as_ferret :store_class_name => true,
:fields => [ ‘field1’,
‘field2’,
:index_components
]

end

def index_components
@index = Array.new
for component in self.components
@index << component.field1.to_s
@index << component.field2.to_s
end
@index.join(" ")
end

Basically, acts_as_ferret will index any model based on the text your
throw at it. Now, something like Product.find_by_contents(“query term”)
should retrieve products based on text in all of its component fields.

Finally, you can do multi_search via:

@results = Product.multi_search(“query term”, [Component])

This search will retrieve both Product and Component models in the array
@results. Now that you have both, you have to check what the class type
is in your view files before displaying the search results:

<% @results.each do |result| %>
<% if result.class == Product %>

code to display your Product here

<% else %>

code to display your Component here

<% end %>
<% end %>

I wasn’t able to go into all the details here, but I hope this helps.

Rami

Graham wrote:

I have been trying to use multi_search to search accross multiple
associated models, but I have had no luck at all. I have scoured the net
and this forum for all similar posts, but none of them contain enough
code for me to get it to work.

I am successfully able to search individual models, and then display the
results without a problem.

I have the following 2 models, Product and Component. The Product model
has_many Components, and the Component model belongs_to Product.

Could anyone provide an example of how they would search the Product
model for a query term, which will then return not only the Products
that match the query, but the Components (related to the Products) as
well.

I would really appreciate a “back-to-basics” example, as I think I have
confused myself completely in my attempts.

Thanks.

Ok… I seem to have got rid of the “nil is not a Symbol” error by
enclosing my @query in “” as below…

@results = Product.multi_search( “@query”, [ Component ] )

The problem now is that it is returning no results. In my development
log, there isn’t even a SQL query like when I use find_by_contents.

Graham wrote:

I have just noticed a glaring typo! In the SearchController, I am using
multi_seach but I should be using multi_search (with the R!) so now I am
getting the “Nil is not a Symbol” error in the browser too.

Hi Rami,

Thanks for the reply… I am still not able to get it to work though. I
am getting the same error that I was getting during my own attempts
(well at one stage anyway!) although when I try in the console, I get a
different error.
Here is my code…

Code

class Product < ActiveRecord::Base

has_many :Components

acts_as_ferret( :store_class_name => true, :fields => [ 

:index_components, ‘name’, ‘description’ ] )

def index_components
  @index = Array.new
  for component in self.components
   @index << component.name.to_s
   @index << component.description.to_s
  end
  @index.join(" ")
end

end

class Component < ActiveRecord::Base

belongs_to :Product

acts_as_ferret( :store_class_name => true, :fields => [ 'name', 

‘description’ ] )

end

class SearchController < ApplicationController

def search
	@query = params[:search] || ''
	unless @query.blank?
		@results = Product.multi_seach( @query, [ Component ] )
end

....

end

End Code

The error I am getting in the browser is, “undefined method
`multi_seach’ for Product:Class” and the error I am getting the console
if I try it manually is, “TypeError: nil is not a symbol”.

This made me think that I need to include the acts_as_ferret plugin
somewhere in my code, but then why would find_by_contents work? Anyway,
at least you have confirmed that my code is correct in my models and
controller. Any ideas on these errors?

Regards,

Graham

Rami wrote:

Graham,

First, to do multi_search make sure to declare :store_class_name => true
in both the Product and Component files in order to do multi_search.

class Product < ActiveRecord::Base
acts_as_ferret :store_class_name => true

end

class Component < ActiveRecord::Base
acts_as_ferret :store_class_name => true

end

Next, if you want to retrieve products based on in its components, you
have to index your product based on the appropriate component values:

class Product < ActiveRecord::Base
acts_as_ferret :store_class_name => true,
:fields => [ ‘field1’,
‘field2’,
:index_components
]

end

def index_components
@index = Array.new
for component in self.components
@index << component.field1.to_s
@index << component.field2.to_s
end
@index.join(" ")
end

Basically, acts_as_ferret will index any model based on the text your
throw at it. Now, something like Product.find_by_contents(“query term”)
should retrieve products based on text in all of its component fields.

Finally, you can do multi_search via:

@results = Product.multi_search(“query term”, [Component])

This search will retrieve both Product and Component models in the array
@results. Now that you have both, you have to check what the class type
is in your view files before displaying the search results:

<% @results.each do |result| %>
<% if result.class == Product %>

code to display your Product here

<% else %>

code to display your Component here

<% end %>
<% end %>

I wasn’t able to go into all the details here, but I hope this helps.

Rami

Graham wrote:

I have been trying to use multi_search to search accross multiple
associated models, but I have had no luck at all. I have scoured the net
and this forum for all similar posts, but none of them contain enough
code for me to get it to work.

I am successfully able to search individual models, and then display the
results without a problem.

I have the following 2 models, Product and Component. The Product model
has_many Components, and the Component model belongs_to Product.

Could anyone provide an example of how they would search the Product
model for a query term, which will then return not only the Products
that match the query, but the Components (related to the Products) as
well.

I would really appreciate a “back-to-basics” example, as I think I have
confused myself completely in my attempts.

Thanks.

The problem now is that it is returning no results. In my development
log, there isn’t even a SQL query like when I use find_by_contents.

Can you check that your product and component models are being properly
indexed by aaf (using the development log)? Its possible you may have a
nil component model which aaf is trying to index. Try adding “unless
self.components.nil?” to your code:

def index_components
unless self.components.nil?
@index = Array.new
for component in self.components
@index << component.name.to_s
@index << component.description.to_s
end
@index.join(" ")
end
end

Also, I would delete your old index folder and have aaf re-create it
next time you startup your app.

Rami

Graham wrote:

Ok… I seem to have got rid of the “nil is not a Symbol” error by
enclosing my @query in “” as below…

@results = Product.multi_search( “@query”, [ Component ] )

The problem now is that it is returning no results. In my development
log, there isn’t even a SQL query like when I use find_by_contents.

Graham wrote:

I have just noticed a glaring typo! In the SearchController, I am using
multi_seach but I should be using multi_search (with the R!) so now I am
getting the “Nil is not a Symbol” error in the browser too.

Hi Rami,

Thanks for the help so far… I deleted the index directories, and then
restarted the webserver. The folders, products & components, have been
created in the index folder, but it doesn’t seem to actually be indexing
anything.

Also, I now no longer get no results, but I have the old “You have a nil
object when you didn’t expect it!” error. This is so frustrating :slight_smile:

find_by_contents works fine everytime… Also, the indexes seem to be
created as well when using this method.

Can we recap quickly? I installed Ferret using gems. I then installed
the AAF plugin using the trunk SVN. Should I be doing anything else at
this point in terms of the installation?

I then made my models & controller look like the code in this post.
First, I used find_by_contents to test it all out, and was able to get
proper results back. I then changed the search method to multi_search
and nothing is returned.

Sorry about this… but I am sure I am doing everything I should be
doing.

Regards,

Graham

Rami wrote:

The problem now is that it is returning no results. In my development
log, there isn’t even a SQL query like when I use find_by_contents.

Can you check that your product and component models are being properly
indexed by aaf (using the development log)? Its possible you may have a
nil component model which aaf is trying to index. Try adding “unless
self.components.nil?” to your code:

def index_components
unless self.components.nil?
@index = Array.new
for component in self.components
@index << component.name.to_s
@index << component.description.to_s
end
@index.join(" ")
end
end

Also, I would delete your old index folder and have aaf re-create it
next time you startup your app.

Rami

I have just noticed a glaring typo! In the SearchController, I am using
multi_seach but I should be using multi_search (with the R!) so now I am
getting the “Nil is not a Symbol” error in the browser too.

On Sun, 2006-08-20 at 14:37 +0200, Graham wrote:

Ok… I seem to have got rid of the “nil is not a Symbol” error by
enclosing my @query in “” as below…

@results = Product.multi_search( “@query”, [ Component ] )

@query” doesn’t use the query variable. Are you sure @query contains
something? Maybe you want params[:query] or something of the sort.

Pedro.

No it definitely contains my search string… I set a breakpoint and
then inspected it in the console.

I think it is because the indexes are not being built. I have been
working on getting Ferret to work without AAF and I am at last getting
somewhere.

Pedro =?ISO-8859-1?Q?C=F4rte-Real?= wrote:

On Sun, 2006-08-20 at 14:37 +0200, Graham wrote:

Ok… I seem to have got rid of the “nil is not a Symbol” error by
enclosing my @query in “” as below…

@results = Product.multi_search( “@query”, [ Component ] )

@query” doesn’t use the query variable. Are you sure @query contains
something? Maybe you want params[:query] or something of the sort.

Pedro.

Yes, I see what you mean… I had taken the “” off before I abandoned
AAF, but it still made no difference.

I have now successfully indexed all my models and can search them all
relative to Product - using Ferret on its own. AAF just did not work for
me.

On Mon, 2006-08-21 at 15:53 +0200, Guest wrote:

No it definitely contains my search string… I set a breakpoint and
then inspected it in the console.

@query might contain your search string but “@query” doesn’t.

For example:

irb(main):001:0> @query = ‘foo’
=> “foo”
irb(main):002:0> @query
=> “foo”
irb(main):003:0> “@query
=> “@query

Putting quotes around it makes it just another string and doesn’t use
the variable at all. To do that you’d have to do:

irb(main):004:0> “#{@query}”
=> “foo”

which is pretty redundant although it will guard against @query being
nil:

irb(main):005:0> “#{@bar}”
=> “”

but then you can just do:

irb(main):007:0> @bar||’’
=> “”

Hope this helps.

Pedro.

On 8/22/06, Graham [email protected] wrote:

Yes, I see what you mean… I had taken the “” off before I abandoned
AAF, but it still made no difference.

I have now successfully indexed all my models and can search them all
relative to Product - using Ferret on its own. AAF just did not work for
me.

Hi Graham,

Just a quick pointer. If you happen to upgrade to Ferret 0.10.0 (it’ll
require some work since the latest version has many non-backwards
compatible changes) then you should use a MultiReader supplied to a
Searcher rather than a MultiSearcher. It’s much more efficient.

reader = IndexReader.new([reader1, reader2, reader3])
searcher = Searcher.new(reader)

Cheers,
Dave