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