One Model With acts_as_list and acts_as_tree
Ruby on Rails provides nice ways to create a list (
acts_as_list
), that is to keep order of items, and to create a tree (acts_as_tree
), that is to organise items with parent–children relationships. But what to do, if you need both functionalities at once?
My model has name Outline
and it holds one textual information.
Firstly we will create a model and its migration:
The output should be:
-
exists app/models/
-
exists test/unit/
-
exists test/fixtures/
-
create app/models/outline.rb
-
create test/unit/outline_test.rb
-
create test/fixtures/outlines.yml
-
create db/migrate
-
create db/migrate/001_create_outlines.rb
The next two sections describe how to modify the generated migration and model files.
Migration
The migration is stored in the generated file db/migrate/001_create_outlines.rb
. Of course, if you already created some migrations, the 001
number will be higher.
The model (and the table too) has to contain columns: parent_id
for the acts_as_tree
declaration, position
for the acts_as_list
declaration and name
to hold textual data.
The content of the migration with three new columns:
Do not forget to apply the new migration:
-
rake db:migrate
This part was simple — the main part of the magic is in the model file…
Model
The model is stored in the generated file app/models/outline.rb
.
Let’s add all necessary parts for acts_as_list
and acts_as_tree
declarations and mix them up gently (thanks to Kris for noticing):
-
span style=”color:#996600;”>"position"
That is it :)
Test
Here are an example, how it works (it is a modified output from ruby script/console
):
-
#testing of the list features
-
"first" #create an instance with name "first"
-
=> #…
-
#its position is 1
-
"second" #create another instance with name "second"
-
=> #…
-
#its position is 2
-
=> 2
-
o2.move_higher #move second item higher
-
#it is on the top; its position is 1
-
#it is necessary to reload it to reflect the previous change
-
=> #…
-
#testing of the tree features
-
"first’s child" #let’s create a child
-
=> #…
-
o1.children << o11 #assign it to its parent
-
=> [#…]
-
#the position is 1, because it is the first child of "first"
-
#what is the parents name? should be "first"
-
=> "first"#what are the children names?
-
first’s child
-
=> [#…]
I hope it will help you. Enjoy
P.S.
This is the previous version of the model that Kris mentioned in his comment.
-
span style=”color:#996600;”>"Outline""Outline""parent_id""position""position"