# HABTM - two lists

**URL:** <https://www.ruby-forum.com/t/habtm-two-lists/58421>\
**Category:** Rails\
**Created:** [April 21, 2006, 3:13pm UTC](https://www.ruby-forum.com/t/habtm-two-lists/58421 "2006-04-21T15:13:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/a8b319/32.png) [@ryan](https://www.ruby-forum.com/u/ryan)\
**Post date:** [April 21, 2006, 3:13pm UTC](https://www.ruby-forum.com/t/habtm-two-lists/58421/1 "2006-04-21T15:13:32Z")

</div>

Does anyone know of a good example somewhere of an implemention for  
adding records with HABTM relations that have lots of possibilities.  
The best way that I’ve seen it done is where you have two lists  
(multiple select lists) where you have the possibilities on the left and  
ones you’ve added on the right with arrows to add and delete items. But  
the only ways I know how to implement that solution are ugly (because  
the form will only submit selected items from the right).

Does anyone know how to implement the two lists elegantly or of another  
solution that works well for many items?

---

<div class="post-metadata">

**Author:** ![ryan](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/a8b319/32.png) [@ryan](https://www.ruby-forum.com/u/ryan)\
**Post date:** [April 22, 2006, 11:00pm UTC](https://www.ruby-forum.com/t/habtm-two-lists/58421/2 "2006-04-22T23:00:34Z")

</div>

I used a tree.js ([http://www.silverstripe.com/downloads/tree/](http://www.silverstripe.com/downloads/tree/))  
controller as my lists  
where somewhat hierarchical so it cut down on the screen real-estate for  
very large lists.

I put two trees on the page side by side, the left tree is what I  
currently have and  
what I can choose from on the right.

I added check boxes to the right hand tree nodes, so I select the ones I  
want and then  
click a button below that basically replaces the items on the left side  
with the ones  
selected on the right.

Example code explains it better I guess 🙂  
This example sets up roles and rights for a standard RBAC.

Rights has\_and\_belongs\_to\_many :roles  
Roles has\_and\_belongs\_to\_many :rights

I setup the data by creating hashes in the controller which are  
available to the view…

# roll everything up into a hierarchical tree structure

# top level is hash of roles

# next level is hash of permissions with controller as key and array

of actions as value  
@role\_tree= {}  
roles= Role.find\_all  
roles.each do |r|  
ph= {}  
rights= r.rights  
rights.each do |p|  
ph[p.controller] ||= []  
ph[p.controller] \<\< p.action  
end  
@role\_tree[r.name] = ph  
end

```
    # creates a tree of controllers with the actions for each 

```

controller  
# top level is hash of controllers  
# next level is an array of actions  
@rights\_tree= {}  
rights= Right.find\_all  
rights.each do |r|  
name= r.controller  
@rights\_tree[name] ||= []  
@rights\_tree[name] \<\< r.action  
end  
end

The view is simple… (edit.rhtml)

# Role and Rights Editor

| Roles | Rights |
| --- | --- |
| \<%= render\_role\_tree(@role\_tree) %\> | \<%= start\_form\_tag :action =\> 'edit' %\> \<%= render\_rights\_tree(@rights\_tree) %\>

The checked items above will replace the Rights of the following Roles:  
 \<% @role\_tree.each\_key do |role| %\> \<%= check\_box\_tag "role", role %\> \<%= role %\> \<% end %\>

\<%= submit\_tag "Allocate to selected Roles" %\> \<%= end\_form\_tag %\>

 |

This part goes in helpers, and creates the html for the two trees this  
is specific for  
the silverstripe tree control)…

module RoleHelper  
def render\_role\_tree(tree)  
ret = ‘’  
ret += “

”

```
    tree.each_key do |r|
        ret += '<li><a href="#">' + r + '</a>' # list roles
        h= tree[r] # get hash of controllers/[actions]
        unless h.empty?
            ret += '<ul>'
            h.each_key do |c|
                ret += '<li><a href="#">' + c + '</a>' # list 

```

controllers  
a= h[c]  
unless a.empty?  
ret += ‘

’  
a.each do |an|  
ret += ‘- ’ + an + ‘
’

# list actions

```
                   end
                   ret += '</ul>'
                end
                ret += '</li>'
            end
            ret += '</ul>'
        end
        ret += '</li>'
    end
    ret += '</ul>'
    ret
end

def render_rights_tree(tree)
    ret = ''
    ret += "<ul class='tree'>"

    tree.each_key do |r|
        ret += "<li><a href=\"#\">#{r}</a>"# list controllers
        aa= tree[r] # get array of actions
        unless aa.empty?
            ret += '<ul>'
            ret += "<li><a href=\"#\" 

```

onclick="checkAll(‘right[#{r}][]’); return  
false;"\>Check All"  
aa.each do |a|  
ret += ‘

- ’ + “\<input type="checkbox"  
name="right[#{r}][]"  
value="#{a}" /\>” + a + ‘
’ # list actions  
end  
ret += ‘’  
end  
ret += ‘’  
end  
ret += ‘’  
ret  
end  
end

the action handler in the controller for the post is a little more  
complicated in my  
case, but basically goes through all the selected checkboxes and sets  
the relevant habtms.

def edit  
if request.post?  
#p params  
unless params[‘role’].nil?  
a\_roles= params[‘role’]  
a\_rights= params[‘right’]  
unless a\_rights.nil?  
a\_roles.each { |ar|  
role= Role.find\_by\_name(ar)  
unless role.nil?  
role.rights.clear  
a\_rights.each { |controller, aa|  
aa.each { |action|  
right=  
Right.find\_by\_controller\_and\_action(controller, action)  
unless right.nil?  
role.rights \<\< right  
#puts “Allocating right  
#{controller}/#{action}  
to #{ar}”  
else  
puts “Right  
#{controller}/#{action} not found”  
end  
}  
}  
else  
puts “Role #{ar} not found”  
end  
}  
flash[:notice]= ‘rights updated’  
else  
flash[:warning]= ‘no rights were selected’  
end  
else  
flash[:warning]= ‘You need to select the role to  
allocate to’  
end  
end

end

Hope that helps and is not too complex 🙂
