I have the following models:
class Book < ActiveRecord::Base
acts_as_ferret
belongs_to :author
end
class Author < ActiveRecord::Base
has_many :books
end
and in the controller:
def search
if params[:query]
@query = params[:query]
@total, @books = Book.full_text_search(@query, :page =>
(params[:page]||1))
@pages = pages_for(@total)
else
@books = []
end
end
I can use the acts_as_ferret plugin to search for a book by title but it
isn''t picking up the authors through the association. So I
can''t do a
search for books by author.
I''ve a feeling I''ve left some config out here. Can anyone help
me out?
--
Posted via http://www.ruby-forum.com/.
Hi Matthew I''m fairly new to AAF as well, but I think if you read through this: http://projects.jkraemer.net/acts_as_ferret/rdoc/classes/FerretMixin/Acts/ARFerret/ClassMethods.html#M000006 it might help you. I think essentially it boils down to the fact that attributes are indexed by default but associations are not, so you might have to pass some options in your call to acts_as_ferret. Pete. -- Posted via http://www.ruby-forum.com/.
To clarify, say your Author class has the fields, ''first_name''
and
''surname''. To have these indexed by the Book class you would
need to do
some things:
1) Create methods in Book.rb to access these fields:
def author_first_name
return author.first_name
end
def author_surname
return author_surname
end
2) Pass these fields as options to the call to acts_as_ferret:
class Book < ActiveRecord::Base
acts_as_ferret :additional_fields =>
[''author_first_name'',
''author_surname'']
belongs_to :author
end
I''m not sure it there''s a more elegant solution, but that
should do the
trick.
Pete.
--
Posted via http://www.ruby-forum.com/.
On Tue, Nov 07, 2006 at 12:08:10AM +0100, Pete Royle wrote: [..]> 1) Create methods in Book.rb to access these fields:[..]> 2) Pass these fields as options to the call to acts_as_ferret: > > class Book < ActiveRecord::Base > acts_as_ferret :additional_fields => [''author_first_name'', > ''author_surname''] > belongs_to :author > end > > I''m not sure it there''s a more elegant solution, but that should do the > trick.that''s exactly what I would have suggested, but please use symbols for field names in your call to acts_as_ferret. cheers, Jens -- webit! Gesellschaft f?r neue Medien mbH www.webit.de Dipl.-Wirtschaftsingenieur Jens Kr?mer kraemer at webit.de Schnorrstra?e 76 Tel +49 351 46766 0 D-01069 Dresden Fax +49 351 46766 66
Thanks Pete. I''ll give this a go. Do you mean:> def author_surname > return author.surname > endand not:> def author_surname > return author_surname > endM. -- Posted via http://www.ruby-forum.com/.
Jens Kraemer wrote:> that''s exactly what I would have suggested, but please use symbols for > field names in your call to acts_as_ferret.So: class Book < ActiveRecord::Base acts_as_ferret :additional_fields => [:author_first_name, :author_surname] belongs_to :author def author_first_name return author.first_name end def author_surname return author.surname end end ? -- Posted via http://www.ruby-forum.com/.
Matthew Planchant wrote:> class Book < ActiveRecord::Base > acts_as_ferret :additional_fields => [:author_first_name, > :author_surname] > belongs_to :author > > def author_first_name > return author.first_name > end > > def author_surname > return author.surname > end > endThis works. Thanks. -- Posted via http://www.ruby-forum.com/.
Will this work with many-to-many relationships?
For example:
class Book < ActiveRecord::Base
acts_as_ferret :additional_fields => [:topic_title]
has_many :book_topics, :dependent => true
has_many :topics, :through => :book_topics
def topic_title
return topic.title
end
end
--
Posted via http://www.ruby-forum.com/.
On Tue, Nov 07, 2006 at 11:35:38AM +0100, Matthew Planchant wrote:> Will this work with many-to-many relationships? > > For example: > > class Book < ActiveRecord::Base > acts_as_ferret :additional_fields => [:topic_title] > > has_many :book_topics, :dependent => true > has_many :topics, :through => :book_topics > > def topic_title > return topic.title > endthis won''t work, as there is no method ''topic'' in your Book class. But you could index the titles of all topics: acts_as_ferret :additional_fields => [:topic_titles] def topic_titles topics.collect { |topic| topic.title }.join '' '' end Jens -- webit! Gesellschaft f?r neue Medien mbH www.webit.de Dipl.-Wirtschaftsingenieur Jens Kr?mer kraemer at webit.de Schnorrstra?e 76 Tel +49 351 46766 0 D-01069 Dresden Fax +49 351 46766 66
Jens Kraemer wrote:> On Tue, Nov 07, 2006 at 11:35:38AM +0100, Matthew Planchant wrote: >> def topic_title >> return topic.title >> end > > this won''t work, as there is no method ''topic'' in your Book class. > But you could index the titles of all topics: > > acts_as_ferret :additional_fields => [:topic_titles] > def topic_titles > topics.collect { |topic| topic.title }.join '' '' > endThanks. I''ll give this a shot. -- Posted via http://www.ruby-forum.com/.
Brendon Muir
2006-Nov-16 06:04 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Hi there, I have a similar problem. I''m building a CMS and we have a
tree model called component_instances. This model has polymorphic
associations with many other models (e.g. Links, Folders, Pages etc...)
I want the user to be able to search for an instance using data stored
in the associated models. To start with in the backend interface, I only
want them to be able to search for items by name, so I came up with
this:
class ComponentInstance < ActiveRecord::Base
has_many :permissions
has_many :groups, :through => :permissions
belongs_to :component #will be in different database ??
acts_as_tree :order => ''position''
acts_as_list :scope => ''parent_id''
belongs_to :instance, :polymorphic => true
acts_as_ferret(
:fields => :instance_name
)
def instance_name
instance.name
end
end
Now that looks like it should work. But when I search for an item by
name (knowing that it exists), nothing shows. I know the search itself
works because becure I added the :fields condition, it would pick up and
return results for the word "folder" as it was used to define the
polymorphic associations on the instances table.
So firstly your help with that problem would be most appreciated. Then
we make things trickier by adding the fact that I''d like the end users
on the front end to be able to search the site not just using the name
field, but basically anything in any of the instance tables.
As a laughing point, when I wrote the original application in PHP using
Mysql fulltext search, the query for the frontend search was 2 pages
long! :)
Looking forward to your great ideas! :)
--
Posted via http://www.ruby-forum.com/.
Jens Kraemer
2006-Nov-16 15:42 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Hi! On Thu, Nov 16, 2006 at 07:04:55AM +0100, Brendon Muir wrote: [..]> acts_as_ferret( > :fields => :instance_name > ) > > def instance_name > instance.name > end > > end > > Now that looks like it should work. But when I search for an item by > name (knowing that it exists), nothing shows. I know the search itself > works because becure I added the :fields condition, it would pick up and > return results for the word "folder" as it was used to define the > polymorphic associations on the instances table.have a look in your development log when you save an instance of class ComponentInstance. There should be a line like ''adding field instance_name with value ...'' showing what value aaf indexed for your instance name. Maybe the instance isn''t there yet when the save takes place ?> So firstly your help with that problem would be most appreciated. Then > we make things trickier by adding the fact that I''d like the end users > on the front end to be able to search the site not just using the name > field, but basically anything in any of the instance tables.that''s easy, just index all the fields you want for frontend and backend search (including the instance_name field) and use a special QueryParser restricted to only the instance_name field for your backend search: QueryParser qp = QueryParser.new(:fields => [:instance_name]) ComponentInstance.find_by_contents(qp.parse user_query) with this solution, backend users could still manually construct complex queries to search other fields, but queries not using any field names will default to only search the instance_name field.> As a laughing point, when I wrote the original application in PHP using > Mysql fulltext search, the query for the frontend search was 2 pages > long! :)dont tell me any details ;-) cheers, Jens -- webit! Gesellschaft f?r neue Medien mbH www.webit.de Dipl.-Wirtschaftsingenieur Jens Kr?mer kraemer at webit.de Schnorrstra?e 76 Tel +49 351 46766 0 D-01069 Dresden Fax +49 351 46766 66
Brendon Muir
2006-Nov-17 02:20 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Jens Kraemer wrote:> Hi! > > On Thu, Nov 16, 2006 at 07:04:55AM +0100, Brendon Muir wrote: > [..] >> Now that looks like it should work. But when I search for an item by >> name (knowing that it exists), nothing shows. I know the search itself >> works because becure I added the :fields condition, it would pick up and >> return results for the word "folder" as it was used to define the >> polymorphic associations on the instances table. > > have a look in your development log when you save an instance of class > ComponentInstance. There should be a line like > ''adding field instance_name with value ...'' > showing what value aaf indexed for your instance name. > > Maybe the instance isn''t there yet when the save takes place ? >I already had a few records in the database so I assumed when i added the ferrit aa that it would index those. I will try adding a new record and see what it says when i get back to work on Monday. :)>> So firstly your help with that problem would be most appreciated. Then >> we make things trickier by adding the fact that I''d like the end users >> on the front end to be able to search the site not just using the name >> field, but basically anything in any of the instance tables. > > that''s easy, just index all the fields you want for frontend and backend > search (including the instance_name field) and use a special QueryParser > restricted to only the instance_name field for your backend search: > > QueryParser qp = QueryParser.new(:fields => [:instance_name]) > ComponentInstance.find_by_contents(qp.parse user_query) > > with this solution, backend users could still manually construct > complex queries to search other fields, but queries not using any field > names will default to only search the instance_name field. >Excellent! Sounds like a good solution. Will this mean I will have to do a while bunch of these type of accessor''s in my model. One for each field in my seperate polymorphic instances? def instance_linkurl instance.linkurl end etc... Will that break when ferret trys to trawl a polymorphic model that doesn''t have a linkurl attribute?>> As a laughing point, when I wrote the original application in PHP using >> Mysql fulltext search, the query for the frontend search was 2 pages >> long! :) > > dont tell me any details ;-) > > cheers, > Jens > > > -- > webit! Gesellschaft f?e Medien mbH www.webit.de > Dipl.-Wirtschaftsingenieur Jens Kr?r kraemer at webit.de > Schnorrstra? 76 Tel +49 351 46766 0 > D-01069 Dresden Fax +49 351 46766 66-- Posted via http://www.ruby-forum.com/.
Jens Kraemer
2006-Nov-20 11:01 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
On Fri, Nov 17, 2006 at 03:20:43AM +0100, Brendon Muir wrote:> Jens Kraemer wrote:[..]> >> So firstly your help with that problem would be most appreciated. Then > >> we make things trickier by adding the fact that I''d like the end users > >> on the front end to be able to search the site not just using the name > >> field, but basically anything in any of the instance tables. > > > > that''s easy, just index all the fields you want for frontend and backend > > search (including the instance_name field) and use a special QueryParser > > restricted to only the instance_name field for your backend search: > > > > QueryParser qp = QueryParser.new(:fields => [:instance_name]) > > ComponentInstance.find_by_contents(qp.parse user_query) > > > > with this solution, backend users could still manually construct > > complex queries to search other fields, but queries not using any field > > names will default to only search the instance_name field. > > > > Excellent! Sounds like a good solution. Will this mean I will have to do > a while bunch of these type of accessor''s in my model. One for each > field in my seperate polymorphic instances? > > def instance_linkurl > instance.linkurl > end > > etc...that depends on what you want to do. If you want fine grained searches on single fields like linkurl or name then yes, you''ll have to have these accessors. but with ruby you can easily declare them in a programmatic way, i.e loop over the attributes of instance and ue define_method inside the loop... if you don''t need that many fields for querying you also can aggregate the values of your instance attributes to a single string and index that instead.> Will that break when ferret trys to trawl a polymorphic model that > doesn''t have a linkurl attribute?it probably will, you''ll have to check if the object has this method and return '''' if it doesn''t. Jens -- webit! Gesellschaft f?r neue Medien mbH www.webit.de Dipl.-Wirtschaftsingenieur Jens Kr?mer kraemer at webit.de Schnorrstra?e 76 Tel +49 351 46766 0 D-01069 Dresden Fax +49 351 46766 66
Brendon Muir
2006-Nov-20 21:44 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Thanks for all your help above :)
Coming back to the original query (now that I''m back at work to try
it),
when I create a "component instance" i get the following in the logs:
Processing FolderController#new (for 127.0.0.1 at 2006-11-21 10:23:29)
[POST]
Session ID: e3154e167b8382c5050468c261bd0ead
Parameters: {"commit"=>"Add",
"folder"=>{"name"=>"cool folder"},
"action"=>"new",
"controller"=>"admin/construction/folder",
"parent_id"=>"12"}
[4;36;1mFolder Columns (0.016000) [0;1mSHOW FIELDS FROM
folders
[4;35;1mSQL (0.000000) BEGIN
[4;36;1mSQL (0.046000) [0;1mINSERT INTO folders (`name`)
VALUES(''cool folder'')
[4;35;1mSQL (0.094000) COMMIT
[4;36;1mComponentInstance Columns (0.016000) [0;1mSHOW FIELDS
FROM component_instances
[4;35;1mComponent Load (0.015000) SELECT * FROM components
WHERE (technical_name = ''folder'') LIMIT 1
[4;36;1mComponent Columns (0.000000) [0;1mSHOW FIELDS FROM
components
[4;35;1mSQL (0.000000) BEGIN
[4;36;1mComponentInstance Load (0.000000) [0;1mSELECT * FROM
component_instances WHERE (parent_id) ORDER BY position DESC LIMIT 1
[4;35;1mSQL (0.032000) INSERT INTO component_instances
(`deleted_root_item`, `instance_type`, `deleted_on`, `enabled`,
`instance_id`, `component_id`, `parent_id`, `position`) VALUES(NULL,
''Folder'', NULL, 1, 4, 2, 12, 5)
ferret_create/update: ComponentInstance : 20
creating doc for class: ComponentInstance, id: 20
[4;36;1mSQL (0.031000) [0;1mCOMMIT
Redirected to
http://localhost:3001/admin/construction/construction_zone/12
Completed in 1.01600 (0 reqs/sec) | DB: 0.25000 (24%) | 302 Found
[http://localhost/admin/construction/folder/12/new]
The current model code is:
class ComponentInstance < ActiveRecord::Base
has_many :permissions
has_many :groups, :through => :permissions
belongs_to :component #will be in different database ??
acts_as_tree :order => ''position''
acts_as_list :scope => ''parent_id''
belongs_to :instance, :polymorphic => true
acts_as_ferret(
:fields => :instance_name
)
def instance_name
instance.name
end
-- And here is the controller method to make a new folder
(component_instance)
def new
if request.post?
@folder = Folder.new(params[:folder])
success = @folder.save
component_instance = ComponentInstance.new
component_instance.enabled = 1; #ie True
component_instance.instance = @folder
component_instance.parent_id = params[:parent_id]
component_instance.component = Component.find(:first, :conditions
=>"technical_name = ''folder''")
if success && component_instance.save
flash[:notice] = ''A new folder was successfully
added.''
redirect_to :controller => ''construction_zone'',
:parent_id =>
params[:parent_id]
else
@folder.destroy if success #Make sure the link and
component_instances tables are consistent
flash[:fail] = ''There was an error when saving the
folder''
end
else
@folder = Folder.new
end
end
Any ideas would be greatly appreciated. :)
Brendon
--
Posted via http://www.ruby-forum.com/.
Brendon Muir
2006-Nov-20 22:39 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Oh so, here''s how to do it :)
acts_as_ferret :fields => [''instance_name'']
def instance_name
instance.name
end
Seems to be the correct syntax :) Not sure why the symbol way didn''t do
it?
Cheers,
Brendon
--
Posted via http://www.ruby-forum.com/.
Jens Kraemer
2006-Nov-21 08:51 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
On Mon, Nov 20, 2006 at 11:39:30PM +0100, Brendon Muir wrote:> Oh so, here''s how to do it :) > > acts_as_ferret :fields => [''instance_name''] > > def instance_name > instance.name > end > > > Seems to be the correct syntax :) Not sure why the symbol way didn''t do > it?imho it''s not the symbol that was the problem, but the missing brackets around it - in your original post you wrote acts_as_ferret :fields => :instance_name So acts_as_ferret :fields => [ :instance_name ] should work, too. Jens> > Cheers, > > Brendon > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Ferret-talk mailing list > Ferret-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/ferret-talk >-- webit! Gesellschaft f?r neue Medien mbH www.webit.de Dipl.-Wirtschaftsingenieur Jens Kr?mer kraemer at webit.de Schnorrstra?e 76 Tel +49 351 46766 0 D-01069 Dresden Fax +49 351 46766 66
Adam Jones
2007-Sep-18 03:31 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
Thanks guys,
The above seems to work for me perfectly except when i add a new not it
doesnt update the index. if i delete and rebuild the index it works
fine. can some one stear me in the right direction please i am guesing i
have to add some metod to the create function in my notes_controller to
update the index ???
Thanks, Adam
my code in contacts_controller:
-------------------
class Contact < ActiveRecord::Base
validates_presence_of :First_Name
validates_presence_of :Last_Name
has_many :notes, :as => :notable
acts_as_ferret :store_class_name => true, :lazy => true, :remote =>
false, :fields =>
{
:First_Name => { :store => :no, :boost => 2 },
:Last_Name => { :store => :no, :boost => 1 },
:description => { :store => :yes, :boost => 0.5 },
:agent_id => { :store => :no, :boost => 0 },
:note_note => { :store => :yes, :boost => 0 }
}
def note_note
@index = Array.new
for note in self.notes
@index << note.note
end
return @index.join(" ")
end
--
Posted via http://www.ruby-forum.com/.
Adam Jones
2007-Sep-18 04:10 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
I think i answered my own question. in the create method for my note i added Contact.find(params[:id]).ferret_create() hooha Adam Jones wrote:> Thanks guys, > > The above seems to work for me perfectly except when i add a new not it > doesnt update the index. if i delete and rebuild the index it works > fine. can some one stear me in the right direction please i am guesing i > have to add some metod to the create function in my notes_controller to > update the index ??? >-- Posted via http://www.ruby-forum.com/.
Jens Kraemer
2007-Sep-20 20:35 UTC
[Ferret-talk] acts_as_ferret with polymorphic associations
On Tue, Sep 18, 2007 at 06:10:38AM +0200, Adam Jones wrote:> I think i answered my own question. > in the create method for my note i added > Contact.find(params[:id]).ferret_create()right, however I''d stick that code in a NotesObserver... Jens> Adam Jones wrote: > > Thanks guys, > > > > The above seems to work for me perfectly except when i add a new not it > > doesnt update the index. if i delete and rebuild the index it works > > fine. can some one stear me in the right direction please i am guesing i > > have to add some metod to the create function in my notes_controller to > > update the index ??? > > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Ferret-talk mailing list > Ferret-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/ferret-talk >-- Jens Kr?mer http://www.jkraemer.net/ - Blog http://www.omdb.org/ - The new free film database
Followed this thread and have a has_many_through association indexing fine. The only problem is the N+1 sql queries incurred with an index rebuild, full or partial. Is there any way to enable eager loading on batch index updates? Cheers, Sam -- Posted via http://www.ruby-forum.com/.
Hi! On Thu, Mar 13, 2008 at 05:01:26AM +0100, Sam Giffney wrote:> Followed this thread and have a has_many_through association indexing > fine. The only problem is the N+1 sql queries incurred with an index > rebuild, full or partial. > > Is there any way to enable eager loading on batch index updates?Yes. Acts_as_ferret defines a class method named records_for_rebuild on your model, which you may override to use a customized find call. See lib/class_methods.rb for the original implementation. Cheers, Jens -- Jens Kr?mer http://www.jkraemer.net/ - Blog http://www.omdb.org/ - The new free film database