Hi, seem to keep running into a wall here. I can''t find any resources on site navigation that can deal with any model being in the nav, allow nesting, and can dynamically update. So I thought about it for a while, and decided on a MenuItems class, which contained the position of the child in relation to it''s siblings, where the parent and the child were polymorphic. Then a given childable object can find it''s parentable by going through the menu_items table. I want my nav to be able to do things like this: --Category1 ----SubCategory1 ------Product1 ------Product2 ----Product3 --Category2 ----Product4 --Page1 --Page2 --Page3 This is the current setup: MODELS class MenuItem < ActiveRecord::Base belongs_to :childable , :polymorphic => true belongs_to :parentable , :polymorphic => true acts_as_list :scope => :parentable_id end class Category < ActiveRecord::Base has_one :parent_menu_item , :as => :parentable , :class_name => ''MenuItem'' has_many :child_menu_items , :as => :childable , :class_name => ''MenuItem'' has_one :parentable , :through => :parent_menu_item has_many :childables , :through => :child_menu_items end class SubCategory < ActiveRecord::Base has_many :child_menu_items , :as => :childable , :class_name => ''MenuItem'' has_one :parent_menu_item , :as => :parentable , :class_name => ''MenuItem'' has_one :parent , :through => :parent_menu_item has_many :children , :through => :child_menu_items end class Page < ActiveRecord::Base has_one :parent_menu_item , :as => :parentable , :class_name => ''MenuItem'' has_one :parent , :through => :parent_menu_item end SCHEMA: ActiveRecord::Schema.define(:version => 20100525184637) do create_table "categories", :force => true do |t| t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end create_table "menu_items", :force => true do |t| t.integer "position", :null => false t.integer "parentable_id", :null => false t.string "parentable_type", :null => false t.integer "childable_id", :null => false t.string "childable_class", :null => false t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end create_table "pages", :force => true do |t| t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end create_table "sub_categories", :force => true do |t| t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end end I have had a lot of trouble with it, this is the best I''ve gotten so far, but I am still getting the error: ActiveRecord::HasManyThroughAssociationPolymorphicError: Cannot have a has_many :through association ''Category#childables'' on the polymorphic object ''Childable#childable''. Is there a way to make this work? Is there a better way to do this? -- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Josh, We''re doing something similar, except that instead of using childable and parentable, we''re using awesome_nested_set. It enables you to have sub_categories within sub_categories, etc., and its interface is pretty intuitive and efficient: http://wiki.github.com/collectiveidea/awesome_nested_set/awesome-nested-set-cheat-sheet Tilde Equals On May 25, 12:29 pm, Josh Cheek <josh.ch...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, seem to keep running into a wall here. I can''t find any resources on > site navigation that can deal with any model being in the nav, allow > nesting, and can dynamically update. > > So I thought about it for a while, and decided on a MenuItems class, which > contained the position of the child in relation to it''s siblings, where the > parent and the child were polymorphic. Then a given childable object can > find it''s parentable by going through the menu_items table. > > I want my nav to be able to do things like this: > --Category1 > ----SubCategory1 > ------Product1 > ------Product2 > ----Product3 > --Category2 > ----Product4 > --Page1 > --Page2 > --Page3 > > This is the current setup: > > MODELS > > class MenuItem < ActiveRecord::Base > belongs_to :childable , :polymorphic => true > belongs_to :parentable , :polymorphic => true > > acts_as_list :scope => :parentable_id > end > > class Category < ActiveRecord::Base > has_one :parent_menu_item , :as => :parentable , :class_name => > ''MenuItem'' > has_many :child_menu_items , :as => :childable , :class_name => > ''MenuItem'' > > has_one :parentable , :through => :parent_menu_item > has_many :childables , :through => :child_menu_items > end > > class SubCategory < ActiveRecord::Base > has_many :child_menu_items , :as => :childable , :class_name => > ''MenuItem'' > has_one :parent_menu_item , :as => :parentable , :class_name => > ''MenuItem'' > > has_one :parent , :through => :parent_menu_item > has_many :children , :through => :child_menu_items > end > > class Page < ActiveRecord::Base > has_one :parent_menu_item , :as => :parentable , :class_name => > ''MenuItem'' > has_one :parent , :through => :parent_menu_item > end > > SCHEMA: > ActiveRecord::Schema.define(:version => 20100525184637) do > > create_table "categories", :force => true do |t| > t.datetime "created_at", :null => false > t.datetime "updated_at", :null => false > end > > create_table "menu_items", :force => true do |t| > t.integer "position", :null => false > t.integer "parentable_id", :null => false > t.string "parentable_type", :null => false > t.integer "childable_id", :null => false > t.string "childable_class", :null => false > t.datetime "created_at", :null => false > t.datetime "updated_at", :null => false > end > > create_table "pages", :force => true do |t| > t.datetime "created_at", :null => false > t.datetime "updated_at", :null => false > end > > create_table "sub_categories", :force => true do |t| > t.datetime "created_at", :null => false > t.datetime "updated_at", :null => false > end > > end > > I have had a lot of trouble with it, this is the best I''ve gotten so far, > but I am still getting the error: > ActiveRecord::HasManyThroughAssociationPolymorphicError: Cannot have a > has_many :through association ''Category#childables'' on the polymorphic > object ''Childable#childable''. > > Is there a way to make this work? Is there a better way to do this?-- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Josh Cheek
2010-May-26 09:49 UTC
Re: Re: Site Navigation With Polymorphic Has Many Through
On Wed, May 26, 2010 at 3:09 AM, Tilde Equals <tildeequals-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Josh, > We''re doing something similar, except that instead of using childable > and parentable, we''re using awesome_nested_set. It enables you to > have sub_categories within sub_categories, etc., and its interface is > pretty intuitive and efficient: > > > http://wiki.github.com/collectiveidea/awesome_nested_set/awesome-nested-set-cheat-sheet > > > Tilde Equals > > > On May 25, 12:29 pm, Josh Cheek <josh.ch...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Hi, seem to keep running into a wall here. I can''t find any resources on > > site navigation that can deal with any model being in the nav, allow > > nesting, and can dynamically update. > > > > So I thought about it for a while, and decided on a MenuItems class, > which > > contained the position of the child in relation to it''s siblings, where > the > > parent and the child were polymorphic. Then a given childable object can > > find it''s parentable by going through the menu_items table. > > > > I want my nav to be able to do things like this: > > --Category1 > > ----SubCategory1 > > ------Product1 > > ------Product2 > > ----Product3 > > --Category2 > > ----Product4 > > --Page1 > > --Page2 > > --Page3 > > > > This is the current setup: > > > > MODELS > > > > class MenuItem < ActiveRecord::Base > > belongs_to :childable , :polymorphic => true > > belongs_to :parentable , :polymorphic => true > > > > acts_as_list :scope => :parentable_id > > end > > > > class Category < ActiveRecord::Base > > has_one :parent_menu_item , :as => :parentable , :class_name => > > ''MenuItem'' > > has_many :child_menu_items , :as => :childable , :class_name => > > ''MenuItem'' > > > > has_one :parentable , :through => :parent_menu_item > > has_many :childables , :through => :child_menu_items > > end > > > > class SubCategory < ActiveRecord::Base > > has_many :child_menu_items , :as => :childable , :class_name => > > ''MenuItem'' > > has_one :parent_menu_item , :as => :parentable , :class_name => > > ''MenuItem'' > > > > has_one :parent , :through => :parent_menu_item > > has_many :children , :through => :child_menu_items > > end > > > > class Page < ActiveRecord::Base > > has_one :parent_menu_item , :as => :parentable , :class_name => > > ''MenuItem'' > > has_one :parent , :through => :parent_menu_item > > end > > > > SCHEMA: > > ActiveRecord::Schema.define(:version => 20100525184637) do > > > > create_table "categories", :force => true do |t| > > t.datetime "created_at", :null => false > > t.datetime "updated_at", :null => false > > end > > > > create_table "menu_items", :force => true do |t| > > t.integer "position", :null => false > > t.integer "parentable_id", :null => false > > t.string "parentable_type", :null => false > > t.integer "childable_id", :null => false > > t.string "childable_class", :null => false > > t.datetime "created_at", :null => false > > t.datetime "updated_at", :null => false > > end > > > > create_table "pages", :force => true do |t| > > t.datetime "created_at", :null => false > > t.datetime "updated_at", :null => false > > end > > > > create_table "sub_categories", :force => true do |t| > > t.datetime "created_at", :null => false > > t.datetime "updated_at", :null => false > > end > > > > end > > > > I have had a lot of trouble with it, this is the best I''ve gotten so far, > > but I am still getting the error: > > ActiveRecord::HasManyThroughAssociationPolymorphicError: Cannot have a > > has_many :through association ''Category#childables'' on the polymorphic > > object ''Childable#childable''. > > > > Is there a way to make this work? Is there a better way to do this? > > -- > 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > To unsubscribe from this group, send email to > rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org<rubyonrails-talk%2Bunsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org> > . > For more options, visit this group at > http://groups.google.com/group/rubyonrails-talk?hl=en. > >I appreciate the suggestion, I had previously used awesomer nested set on a project. I had two issues with it. The first was that the reason for using it was so that you could query for any level of children with one db query, but when I then went to ask each element for it''s children, I found that it was re-querying, so this purpose was unrealized. (possibly this behaviour has been resolved?) The way to get around it was to transform the results into something usable, ie hashes of hashes, or arrays of arrays, etc. But this was not provided by the plugin, and coupled a lot of code. In the end, I spent about 8 hours writing a method that would iterate through the results one time, accepting lambdas for what to do before entering a deeper level, after leaving it, and what should be done to display a single element. It got pretty ugly, and may have been an example of premature optimization, probably caching would have made the large number of database queries irrelevant, but the real reason I had to do that at all was to mimic a tree like structure, which is what a many to many association already provides. So I don''t really see much benefit to the nested sets data structure. Also, I''m not sure how well it integrates with polymorphism. In my case, Categories and SubCategories will have different attributes, and Pages will be drastically different than either of these. They all need to be in the navigation. In my previous attempt, I queried for each object that the menu item was representing, but again, that seems inefficient. To be fair, though, when I tried last, i was still very new to Ruby and Rails. I thought a polymorphic has_many :through would keep things clean, give me the tree structure I need for creating nested <ul> in my html, and dry up the associations between elements. Of course, it doesn''t have the inherent ordering that nested sets do, which is why I also have acts_as_list positions on the join table. At present, I''m probably going to give this plugin a try: http://github.com/fauna/has_many_polymorphs/tree/bcd9626411c9d0658ab527f1e6a0d0622e4f6e15 If it goes well, I''ll report back here. If my above statements represented an incorrect assessment, please correct me. If there is some obvious solution that I am missing, please guide me to it. -Josh -- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.