I used a tree.js (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)
<h1>Role and Rights Editor</h1>
<table cellspacing="10" cellpadding="20%">
<tr>
<th align="left">Roles</th>
<th align="left">Rights</th>
<tr>
<td valign="top"><%= render_role_tree(@role_tree)
%></td>
<td><%= start_form_tag :action => ''edit'' %>
<%= render_rights_tree(@rights_tree) %>
<p>
The checked items above will replace the Rights of the following
Roles:<br>
<% @role_tree.each_key do |role| %>
<%= check_box_tag "role", role %> <%= role %>
<% end %>
<p>
<%= submit_tag "Allocate to selected Roles" %>
<%= end_form_tag %>
</td>
</table>
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 += "<ul class=''tree''>"
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 += ''<ul>''
a.each do |an|
ret += ''<li><a
href="#">'' + an +
''</a></li>'' # 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</a>"
aa.each do |a|
ret += ''<li>'' + "<input
type=\"checkbox\" name=\"right[#{r}][]\"
value=\"#{a}\" />" + a + ''</li>'' #
list actions
end
ret += ''</ul>''
end
ret += ''</li>''
end
ret += ''</ul>''
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|
rightRight.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 :)
Ryan wrote:> 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?
>