If I have three models: Library has_many :shelves Shelf belongs_to :library and has_many :books Book belongs_to :shelf What is the most efficient way to get all of the books in a Library? Of course the models could be designed so that there is a direct library-book shortcut relationship as well, but assuming that doesn''t exist... This does not work but I''m looking for something equivalent: @books = @library.shelves.books Is it best to start with books and include shelf? Like this: @books = Book.find(:all, :include => :shelf, :conditions => [''shelves.library_id = ?'', @library.id] I don''t believe the above works with great-grandchildren however so I''m curious about that as well. For example if Book has_many :pages and I want to know all the pages in a certain library. I know it''s always possible with multiple database calls but wondering what is the most efficent way. Thanks!! -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
On 10/9/06, Carl Johnson <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > > If I have three models: > > Library has_many :shelves > Shelf belongs_to :library and has_many :books > Book belongs_to :shelf > > What is the most efficient way to get all of the books in a Library? > > Of course the models could be designed so that there is a direct > library-book shortcut relationship as well, but assuming that doesn''t > exist... > > This does not work but I''m looking for something equivalent: > > @books = @library.shelves.books > > Is it best to start with books and include shelf? Like this: > > @books = Book.find(:all, :include => :shelf, :conditions => > [''shelves.library_id = ?'', @library.id]No, like this: @books = Book.find(:all, :conditions => [''shelves.library_id = ?'', @library.id], :include=>{:shelf=>{:books=>:pages}} You can nest this as much as you like. Just be aware of the slightly quirky naming conventions for the table aliases, in case you want to add conditions to the child or grandchild tables. Have a look at the Rails doco for Association. Cheers, Max --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
> @books = Book.find(:all, :conditions => > [''shelves.library_id = ?'', @library.id], > :include=>{:shelf=>{:books=>:pages}} > > You can nest this as much as you like.Ah perfect! I knew there must be a Rails way to do the joins. Thanks very much! -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
On 10/9/06, Carl Johnson <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > > If I have three models: > > Library has_many :shelves > Shelf belongs_to :library and has_many :books > Book belongs_to :shelf > > What is the most efficient way to get all of the books in a Library? > > Of course the models could be designed so that there is a direct > library-book shortcut relationship as well, but assuming that doesn''t > exist... > > This does not work but I''m looking for something equivalent: > > @books = @library.shelves.books > > Is it best to start with books and include shelf? Like this: > > @books = Book.find(:all, :include => :shelf, :conditions => > [''shelves.library_id = ?'', @library.id] > > I don''t believe the above works with great-grandchildren however so I''m > curious about that as well. For example if Book has_many :pages and I > want to know all the pages in a certain library. I know it''s always > possible with multiple database calls but wondering what is the most > efficent way. > > Thanks!!This is a classic example of why :through was added to has_many in 1.1 - see the excellent tutorials at: http://blog.hasmanythrough.com/articles/2006/02/28/association-goodness http://blog.hasmanythrough.com/articles/2006/03/01/association-goodness-2 Essentially, you add an additional declaration to Library: has_many :books, :through => :shelves And then you can say @books = @library.books and everything should work normally. Not sure about the next level (library->shelf->book->page) - any hm:t experts want to offer some advice? -- Matt Jones mdj.acme-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org President/Technical Director, Acme Art Company (acmeartco.org) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Max hit the fastest solution on it with find() and :include, but at the end of the day, these are all Ruby enumerables, so you can fall back onto Ruby operators (albeit at the cost of more SQL queries): @pages = library.shelves.map { |s| s.books.map { |b| b.pages } } }.flatten Matt Jones wrote:> Not sure about the next level (library->shelf->book->page) - any hm:t > experts want to offer some advice?--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Carl Johnson <rails-mailing-list@...> writes:> > > > <at> books = Book.find(:all, :conditions => > > [''shelves.library_id = ?'', <at> library.id], > > :include=>{:shelf=>{:books=>:pages}} > > > > You can nest this as much as you like. > > Ah perfect! I knew there must be a Rails way to do the joins. Thanks > very much! >Be careful though. As you join more tables together, if you don''t have enough indexing on the columns which are being joined then your queries will really start to drag as more data is added. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---