问题
I've read Rails guides and tried a few different things w/Active Record but haven't been able to figure out what the best way to do this is.
I need to set up a self-referential (users to users) relationship that is hierarchical. It usually would be no more than 5 levels high, but should be able to scale up infinitely.
I've tried creating a UserHierarchy model with a DB schema like this:
parent | child | level
However, managing this is a bit too difficult and too complicated to handle.
What's the best way in Rails to do a self-referential hierarchical relationship? I've checked out gems like ancestry, but the majority of them use class inheritance and don't work well for self-referential relationships. It's a many-to-many, self-referential hierarchy (in MySQL).
回答1:
Ancestry is one of the gems that is esp. well suited for object tree structures (what you call self-referential hierarchical relationships). You should have a more detailed look at it.
Generally, there are about four common ways to store trees in a SQL database:
- Simple parent pointers. You just add a new column called
parent_idto your model holding the ID of the parent object. This allows easy inserts and is well suited for single-level hierarchies but is generally difficult to use for deeper hierarchies and is thus generally not used as the primary mechanism (although it is sometimes combined with other mechanisms) - Nested Sets. You define your trees as a structure of nested sets. This is typically implemented with a
rightand aleftcolumn which are populated with numbers to define the set. It allows efficient querying but is a bit tricky when inserting values. Esp. when having concurrent changes to a tree, it is sometimes prone to inconsistencies. This model is e.g. used to the awesome_nested_set gem. - Materialized Paths. This is the model e.g. used by ancestry. It stores the full parent path of all elements. This allows for efficient inserting and querying. Changing a tree is bit more expensive.
- Closure Trees. This mechanism stores for each element all of its parents in a table. This is e.g. used by the closure_tree gem.
Generally, all these options allow to store a tree of objects, i.e. a hierarchical structure of objects of the same class (an ActiveRecord model in this case).
Which one to use depends on which trade-offs are more important for your specific use-case. Most importantly, you should figure out if you are changing trees often (e.g. moving sub-trees around or adding only leaves) and how you are querying the tree (e.g. do you only need direct children, do you need whole sub-trees, do you need to filter) and chose the appropriate solution based on that.
来源:https://stackoverflow.com/questions/29265133/rails-self-referential-hierarchical-relationship