[Ovirt-devel] [PATCH] refactored popups and grids to pull more into the layouts, and static js functions into ovirt.js.

Scott Seago sseago at redhat.com
Thu May 29 19:54:19 UTC 2008


Also, the children and all_children methods on Pool now accept find parameters.

Signed-off-by: Scott Seago <sseago at redhat.com>
---
 wui/src/app/controllers/application.rb             |   24 +-
 wui/src/app/controllers/hardware_controller.rb     |   46 ++-
 wui/src/app/controllers/host_controller.rb         |    3 -
 wui/src/app/controllers/storage_controller.rb      |    2 +-
 wui/src/app/models/pool.rb                         |   11 +-
 wui/src/app/views/dashboard/index.html.erb         |   50 --
 wui/src/app/views/hardware/move.rhtml              |   13 +-
 wui/src/app/views/hardware/new.html.erb            |   38 +-
 wui/src/app/views/hardware/show_hosts.rhtml        |    1 +
 wui/src/app/views/hardware/show_storage.rhtml      |    1 +
 wui/src/app/views/host/_grid.rhtml                 |   21 +-
 wui/src/app/views/host/addhost.html.erb            |   71 +--
 wui/src/app/views/layouts/popup.rhtml              |    7 +-
 wui/src/app/views/layouts/redux.rhtml              |   64 +--
 wui/src/app/views/permission/new.rhtml             |   26 +-
 wui/src/app/views/resources/new.rhtml              |   27 +-
 wui/src/app/views/resources/show.rhtml             |   78 ---
 wui/src/app/views/storage/_grid.rhtml              |   11 +-
 wui/src/app/views/storage/addstorage.html.erb      |   48 +-
 wui/src/app/views/storage/new.rhtml                |   42 +-
 wui/src/app/views/vm/new.rhtml                     |   28 +-
 wui/src/public/javascripts/ovirt.js                |  138 +++++
 .../betternestedset/lib/#better_nested_set.rb#     |  583 --------------------
 .../betternestedset/lib/better_nested_set.rb       |   33 +-
 24 files changed, 350 insertions(+), 1016 deletions(-)
 create mode 100644 wui/src/public/javascripts/ovirt.js
 delete mode 100644 wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb#

diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb
index 5f20be3..3ca5125 100644
--- a/wui/src/app/controllers/application.rb
+++ b/wui/src/app/controllers/application.rb
@@ -84,18 +84,30 @@ class ApplicationController < ActionController::Base
       end
     end
   end
-  def json_list(full_items, attributes)
+
+  # don't define find_opts for array inputs
+  def json_list(full_items, attributes, arg_list=[], find_opts={})
     page = params[:page].to_i
-    item_list = full_items.paginate(:page => page, 
-                                    :order => "#{params[:sortname]} #{params[:sortorder]}", 
-                                    :per_page => params[:rp])
+    paginate_opts = {:page => page, 
+                     :order => "#{params[:sortname]} #{params[:sortorder]}", 
+                     :per_page => params[:rp]}
+    arg_list << find_opts.merge(paginate_opts)
+    item_list = full_items.paginate(*arg_list)
     json_hash = {}
     json_hash[:page] = page
-    json_hash[:total] = full_items.size
+    json_hash[:total] = item_list.total_entries
     json_hash[:rows] = item_list.collect do |item|
       item_hash = {}
       item_hash[:id] = item.id
-      item_hash[:cell] = attributes.collect {|attr| item.send(attr)}
+      item_hash[:cell] = attributes.collect do |attr| 
+        if attr.is_a? Array
+          value = item
+          attr.each { |attr_item| value = value.send(attr_item)}
+          value
+        else
+          item.send(attr)
+        end
+      end
       item_hash
     end
     render :json => json_hash.to_json
diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb
index ad857f1..0f0c904 100644
--- a/wui/src/app/controllers/hardware_controller.rb
+++ b/wui/src/app/controllers/hardware_controller.rb
@@ -229,17 +229,27 @@ class HardwareController < ApplicationController
     if params[:id]
       pre_json
       hosts = @pool.hosts
+      find_opts = {}
+      include_pool = false
     else
-      # FIXME: no permissions checks here yet, no filtering of current pool yet
-      hosts = Host.find(:all)
+      # FIXME: no permissions or usage checks here yet
+      # filtering on which pool to exclude
+      id = params[:exclude_id]
+      hosts = Host
+      find_opts = {:include => :hardware_pool, 
+        :conditions => ["pools.id != ?", id]}
+      include_pool = true
     end
-    json_list(hosts, 
-              [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str])
+    attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str]
+    attr_list.insert(2, [:hardware_pool, :name]) if include_pool
+    json_list(hosts, attr_list, [:all], find_opts)
   end
 
   def vm_pools_json
-    json_list(@pool.sub_vm_resource_pools, 
-              [:id, :name])
+    json_list(Pool, 
+              [:id, :name], 
+              [@pool, :children],
+              {:finder => 'call_finder', :conditions => ["type = 'VmResourcePool'"]})
   end
 
   def users_json
@@ -251,12 +261,20 @@ class HardwareController < ApplicationController
     if params[:id]
       pre_json
       storage_pools = @pool.storage_pools
+      find_opts = {}
+      include_pool = false
     else
-      # FIXME: no permissions checks here yet, no filtering of current pool yet
-      storage_pools = StoragePool.find(:all)
+      # FIXME: no permissions or usage checks here yet
+      # filtering on which pool to exclude
+      id = params[:exclude_id]
+      storage_pools = StoragePool
+      find_opts = {:include => :hardware_pool, 
+        :conditions => ["pools.id != ?", id]}
+      include_pool = true
     end
-    json_list(storage_pools, 
-              [:id, :display_name, :ip_addr, :get_type_label])
+    attr_list = [:id, :display_name, :ip_addr, :get_type_label]
+    attr_list.insert(2, [:hardware_pool, :name]) if include_pool
+    json_list(storage_pools, attr_list, [:all], find_opts)
   end
 
   def storage_volumes_json
@@ -283,8 +301,10 @@ class HardwareController < ApplicationController
     resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} if resource_ids_str
     begin
       @pool.create_with_resources(@parent, resource_type, resource_ids)
-      render :json => { :object => "pool", :success => true, 
+      reply = { :object => "pool", :success => true, 
                         :alert => "Hardware Pool was successfully created." }
+      reply[:resource_type] = resource_type if resource_type
+      render :json => reply
     rescue
       render :json => { :object => "pool", :success => false, 
                         :errors => @pool.errors.localize_error_messages.to_a  }
@@ -308,7 +328,7 @@ class HardwareController < ApplicationController
   # in addition to the current pool (which is checked). We also need to fail
   # for hosts that aren't currently empty
   def add_hosts
-    host_ids_str = params[:host_ids]
+    host_ids_str = params[:resource_ids]
     host_ids = host_ids_str.split(",").collect {|x| x.to_i}
 
     begin
@@ -347,7 +367,7 @@ class HardwareController < ApplicationController
   # in addition to the current pool (which is checked). We also need to fail
   # for storage that aren't currently empty
   def add_storage
-    storage_pool_ids_str = params[:storage_pool_ids]
+    storage_pool_ids_str = params[:resource_ids]
     storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i}
     
     begin
diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb
index f89997f..623cc0c 100644
--- a/wui/src/app/controllers/host_controller.rb
+++ b/wui/src/app/controllers/host_controller.rb
@@ -58,9 +58,6 @@ class HostController < ApplicationController
 
   def addhost
     @hardware_pool = Pool.find(params[:hardware_pool_id])
-    @unassigned = Pool.root.hosts.size
-    # FIXME: @assigned should match  the updated assigned hosts query when that's done
-    @assigned = Host.find(:all).size
     render :layout => 'popup'    
   end
 
diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb
index 1c5b392..c8831e6 100644
--- a/wui/src/app/controllers/storage_controller.rb
+++ b/wui/src/app/controllers/storage_controller.rb
@@ -88,7 +88,7 @@ class StorageController < ApplicationController
 
   def new2
     @storage_pools = @storage_pool.hardware_pool.storage_volumes
-    render :layout => 'popup'    
+    render :layout => false
   end
 
   def insert_refresh_task
diff --git a/wui/src/app/models/pool.rb b/wui/src/app/models/pool.rb
index 490c5e6..5390beb 100644
--- a/wui/src/app/models/pool.rb
+++ b/wui/src/app/models/pool.rb
@@ -69,10 +69,10 @@ class Pool < ActiveRecord::Base
   end
 
   def sub_hardware_pools
-    Pool.select_hardware_pools(children)
+    children({:conditions => "type='HardwarePool'"})
   end
   def sub_vm_resource_pools
-    Pool.select_vm_pools(children)
+    children({:conditions => "type='VmResourcePool'"})
   end
   def self_and_like_siblings
     self_and_siblings.select {|pool| pool[:type] == self.class.name}
@@ -156,7 +156,12 @@ class Pool < ActiveRecord::Base
       hash
     end
   end
-    
+
+  def self.call_finder(*args)
+    obj = args.shift
+    method = args.shift
+    obj.send(method, *args)
+  end    
 
   protected
   def traverse_parents
diff --git a/wui/src/app/views/dashboard/index.html.erb b/wui/src/app/views/dashboard/index.html.erb
index 8715261..92cb4da 100644
--- a/wui/src/app/views/dashboard/index.html.erb
+++ b/wui/src/app/views/dashboard/index.html.erb
@@ -1,57 +1,7 @@
-    <div id="data">
-      <div class="inside">
-
-         <div id="dataTableWrapper">
-
-          <%= render :partial => "/layouts/quick_stats", :locals => { :hpool => @default_pool, :vms => @vms } %>
-
-          <div class="dataTable">
-
-              <%= render :partial => "/layouts/hardware_pool_type_list", :locals => { :hardware_pools => @hardware_pools } %>
-
-            </div> <!-- end #dataTable -->
-
-            <div class="data-section">
-              <div class="data-section-header"><strong>Available Hosts (<%= @available_hosts.size %>)</strong></div>
-              <div class="data-section-stats">Statistics Data</div>
-              <div class="data-section-table">
-                <div class="inside">
-                  <%= render :partial => "/host/list", :locals => { :hosts => @available_hosts } %>
-                </div>
-              </div>
-            </div>
-
-            <div class="data-section">
-              <div class="data-section-header"><strong>Available Storage (<%= @available_storage_volumes.size %>)</strong></div>
-              <div class="data-section-header"><strong>Storage Pools (<%= @storage_pools.size %>)</strong></div>
-              <div class="data-section-stats">Statistics Data</div>
-              <div class="data-section-table">
-                <div class="inside">
-                  <%= render :partial => "/storage/list_volumes", :locals => { :storage_volumes => @available_storage_volumes } %>
-                </div>
-              </div>
-            </div>
-
-          </div> <!-- end #dataTableWrapper -->
-
-      </div> <!-- end #data.inside -->
-      </div> <!-- end #data -->
-
-  </td>
   <td id="right">
-          <div class="heading"> </div>
           <div class="tools">
 
           <h3>Actions</h3>
-          <%if @can_modify -%>
-          <div class="actions">
-<!--
-              <%= link_to 'Add Storage', { :controller => 'storage', :action => 'new', :hardware_pool_id => @default_pool}, { :class => "create" } %>
-              <hr/>
--->
-              <%= link_to 'Create New Pool', { :controller => "hardware", :action => 'new', :parent_id => @default_pool}, { :class => "create" } %>
-          </div>
-          <% end -%>
 
           <div class="actions">
             <div><%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %></div>
diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml
index 190fc03..f5824c6 100644
--- a/wui/src/app/views/hardware/move.rhtml
+++ b/wui/src/app/views/hardware/move.rhtml
@@ -1,3 +1,10 @@
+<%- content_for :title do -%>
+  Move  <%= @resource_type.capitalize %>
+<%- end -%>
+<%- content_for :description do -%>
+  Select an existing hardware pool or create a new pool for selected <%= @resource_type %>. 
+<%- end -%>
+
 <script type="text/javascript">
       $(document).ready(function(){         
         $("#move_tree").treeview({
@@ -34,12 +41,7 @@ $('#move_to_new_pool').click(function(){
 });
 </script>
 
-<div id="window">
 
-<div class="dialog_title_small">
-	<div class="header">Move  <%= @resource_type.capitalize %></div>
-    <div>Select an existing hardware pool or create a new pool for selected <%= @resource_type %>. </div>
-</div>
 
 <div class="dialog_tree">
   <ul id="move_tree" class="filetree treeview-famfamfam treeview"></ul>
@@ -63,4 +65,3 @@ $('#move_to_new_pool').click(function(){
           <div class="button_right_blue"></div>
         </div> 
 </div>
-</div>
diff --git a/wui/src/app/views/hardware/new.html.erb b/wui/src/app/views/hardware/new.html.erb
index a533871..f594009 100644
--- a/wui/src/app/views/hardware/new.html.erb
+++ b/wui/src/app/views/hardware/new.html.erb
@@ -1,40 +1,30 @@
-<div class="dialog_title_small">
-  <div class="header">Add New Hardware Pool</div>
-  <div>Add a new Hardware Pool to the <%= @parent.name %> pool.
-    <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %>
-  </div>
-</div>
+<%- content_for :title do -%>
+  <%= _("Add New Hardware Pool") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Add a new Hardware Pool to the <%= @parent.name %> pool.
+  <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %>
+<%- end -%>
 
 <form method="POST" action="<%= url_for :action => 'create' %>" id="pool_form" >
-<div class="dialog_form">
-  <%= render :partial => 'form' %>
-</div>
-<%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %>
+  <div class="dialog_form">
+    <%= render :partial => 'form' %>
+  </div>
+  <%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %>
 </form>
-  <script type="text/javascript">
+
+<script type="text/javascript">
 $(function() {
     var hwpooloptions = {
         target:        '<%= url_for :action => 'create' %>',   // target element to update
 	dataType:      'json',
-        success:       afterNewHwPool  // post-submit callback
+        success:       afterHwPool  // post-submit callback
     };
 
     // bind form using 'ajaxForm' 
     $('#pool_form').ajaxForm(hwpooloptions); 
 });
-function afterNewHwPool(response, status){
-    ajax_validation(response, status)
-    if (response.success) {
-      jQuery(document).trigger('close.facebox');
-      // FIXME do we need to reload the tree here
-      <%= "$('##{@resource_type}_grid').flexReload()" if @resource_type %>
-      //$("#vmpools_grid").flexReload()
-    }
-}
 </script>
 
-<%- content_for :title do -%>
-<%= _("New Hardware Pool") %>
-<%- end -%>
 
 
diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml
index ae0e8af..bcbc2b8 100644
--- a/wui/src/app/views/hardware/show_hosts.rhtml
+++ b/wui/src/app/views/hardware/show_hosts.rhtml
@@ -51,6 +51,7 @@
     <div class="data_section">
        <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid",
                                                          :hwpool_id => @pool.id,
+                                                         :exclude_id => nil,
                                                          :on_select => "hosts_select" } %>
     </div>
 <div class="selection_detail" id="hosts_selection">
diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml
index 3d547db..f0b14bc 100644
--- a/wui/src/app/views/hardware/show_storage.rhtml
+++ b/wui/src/app/views/hardware/show_storage.rhtml
@@ -68,6 +68,7 @@
 <div class="data_section">
        <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid",
                                                             :hwpool_id => @pool.id,
+                                                         :exclude_id => nil,
                                                          :on_select => "storage_select" } %>
 </div>
 
diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml
index 338bc78..25bdfd7 100644
--- a/wui/src/app/views/host/_grid.rhtml
+++ b/wui/src/app/views/host/_grid.rhtml
@@ -7,18 +7,19 @@
 	$("#<%= table_id %>").flexigrid
 	(
 	{
-	url: '<%=  url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id %>',
+	url: '<%=  url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id, :exclude_id => exclude_id %>',
 	dataType: 'json',
 	colModel : [
-		{display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
-		{display: 'Hostname', name : 'hostname', width : 60, sortable : true, align: 'left'},
-	        {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'},
-		{display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, sortable : true, align: 'left'},
-		{display: 'CPUs', name : 'num_cpus', width : 40, sortable : true, align: 'left'},
-		{display: 'Speed (MHz)', name : 'cpu_speed', width : 60, sortable : true, align: 'right'},
-		{display: 'Arch', name : 'arch', width : 50, sortable : true, align: 'right'},
-		{display: 'RAM (MB)', name : 'memory', width : 60, sortable : true, align: 'right'},
-		{display: 'Disabled', name : 'is_disabled', width : 50, sortable : true, align: 'right'}
+		{display: '', width : 20, align: 'left', process: <%= table_id %>checkbox},
+		{display: 'Hostname', name : 'hostname', width : 60, align: 'left'},
+		<%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %>
+	        {display: 'UUID', name : 'uuid', width : 180, align: 'left'},
+		{display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, align: 'left'},
+		{display: 'CPUs', name : 'num_cpus', width : 40, align: 'left'},
+		{display: 'Speed (MHz)', name : 'cpu_speed', width : 60, align: 'right'},
+		{display: 'Arch', name : 'arch', width : 50, align: 'right'},
+		{display: 'RAM (MB)', name : 'memory', width : 60, align: 'right'},
+		{display: 'Disabled', name : 'is_disabled', width : 50, align: 'right'}
 		],
 	sortname: "hostname",
 	sortorder: "asc",
diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb
index 69e0e66..bc3c797 100644
--- a/wui/src/app/views/host/addhost.html.erb
+++ b/wui/src/app/views/host/addhost.html.erb
@@ -1,55 +1,18 @@
-<div class="dialog_title">
-	<div class="header">Add Host</div>
-    <div>Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool.  <a href="#">Learn how to manage hosts</a></div>
+<%- content_for :title do -%>
+  <%= _("Add Host") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool.  <a href="#">Learn how to manage hosts</a>
+<%- end -%>
+
+<div class="panel_header"></div>
+<div class="dialog_body">
+  <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_grid",
+             :hwpool_id => nil, :exclude_id => @hardware_pool.id, 
+             :on_select => "false"  } %>
 </div>
-<div id="toolbar_nav">
-<ul>
-    <li class="current" id="unassigned_tab"><a href="#" onClick = "show_unassigned()"><img style="vertical-align:middle;" src="" />  Unassigned Hosts (<%= @unassigned %>)</a></li>
-    <li id="assigned_tab"><a href="#" onClick = "show_assigned()"><img style="vertical-align:middle;" src="" />  Assigned Hosts (<%= @assigned %>)</a></li>
-</ul>
-</div>
-<script type="text/javascript">
-  function show_unassigned()
-  {
-      $("#assigned_tab").removeClass('current');
-      $("#unassigned_tab").addClass('current');
-      $("#addhosts_assigned_grid_div").hide()
-      $("#addhosts_unassigned_grid_div").show()
-  }
-  function show_assigned()
-  {
-      $("#assigned_tab").addClass('current');
-      $("#unassigned_tab").removeClass('current');
-      $("#addhosts_unassigned_grid_div").hide()
-      $("#addhosts_assigned_grid_div").show()
-  }
-  function add_hosts()
-  {
-    var assigned_selected= get_selected_checkboxes(document.addhosts_assigned_grid_form)
-    var unassigned_selected= get_selected_checkboxes(document.addhosts_unassigned_grid_form)
-    var hosts = Array.concat(assigned_selected,unassigned_selected)
-    if (validate_selected(hosts, "host")) {
-      $.post('<%= url_for :controller => "hardware", :action => "add_hosts", :id => @hardware_pool %>',
-             { host_ids: hosts.toString() },
-              function(data,status){ 
-                jQuery(document).trigger('close.facebox');
-                $("#hosts_grid").flexReload()
-		if (data.alert) {
-		  alert(data.alert);
-                }
-               }, 'json');
-    }
-  }
-</script>
-  <div class="panel_header"></div>
-  <div class="dialog_body">
-       <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_unassigned_grid",
-           :hwpool_id => Pool.root.id, :on_select => "false"  } %>
-       <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_assigned_grid",
-           :hwpool_id => nil, :on_select => "false" } %>
-  </div>
-</div>
-<script type="text/javascript">
-  $("#addhosts_assigned_grid_div").hide()
-</script>
-<%= popup_footer("add_hosts()", "Add Hosts") %>
+
+<%= popup_footer("add_hosts('#{url_for :controller => "hardware", 
+                                      :action => "add_hosts", 
+                                      :id => @hardware_pool}')", 
+                 "Add Hosts") %>
diff --git a/wui/src/app/views/layouts/popup.rhtml b/wui/src/app/views/layouts/popup.rhtml
index 736517c..55dda58 100644
--- a/wui/src/app/views/layouts/popup.rhtml
+++ b/wui/src/app/views/layouts/popup.rhtml
@@ -1,2 +1,7 @@
-<%# currently nothing for popups here. %>
+<div id="window">
+<div class="dialog_title_small">
+  <div class="header"><%= yield :title -%></div>
+  <div><%= yield :description -%></div>
+</div>
 <%= yield  %> 
+</div>
diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml
index 72a49f8..63a9a56 100644
--- a/wui/src/app/views/layouts/redux.rhtml
+++ b/wui/src/app/views/layouts/redux.rhtml
@@ -27,6 +27,9 @@
   <%= javascript_include_tag "ui.slider.js" -%>
   <%= javascript_include_tag "jquery.cookie.js" -%>
   <%= javascript_include_tag "jquery.form.js" -%>
+
+  <!-- ovirt-specific functions defined here
+  <%= javascript_include_tag "ovirt.js" -%>
     <script type="text/javascript">
       $(document).ready(function(){         
         $("#tree").treeview({
@@ -39,67 +42,10 @@
             action_type: "hyperlink"
 	    })
 	}); 
-        
-  function get_selected_checkboxes(obj_form)
-  {
-    var selected_array = new Array()
-    var selected_index = 0
-    var checkboxes
-    if (obj_form.grid_checkbox) {
-      if (obj_form.grid_checkbox.length == undefined) {
-        checkboxes = [obj_form.grid_checkbox]
-      } else {
-        checkboxes = obj_form.grid_checkbox
-      }
-      for(var i=0; i < checkboxes.length; i++){
-      if(checkboxes[i].checked)
-        {
-          selected_array[selected_index]= checkboxes[i].value
-          selected_index++
-        }
-      }
-    }
-    return selected_array
-  }
-  function validate_selected(selected_array, name)
-  {
-    if (selected_array.length == 0) {
-      alert("Please select at least one " + name + "  to continue")
-      return false
-    } else {
-      return true
-    }
-  }
-  function ajax_validation(response, status)
-  {
-    if (response.object) {
-      $(".fieldWithErrors").removeClass("fieldWithErrors");
-      $("div.errorExplanation").remove();
-      if (!response.success) {
-        for(i=0; i<response.errors.length; i++) { 
-          var element = $("div.form_field:has(#"+response.object + "_" + response.errors[i][0]+")");
-          if (element) {
-            element.addClass("fieldWithErrors");
-            for(j=0; j<response.errors[i][1].length; j++) { 
-              element.append('<div class="errorExplanation">'+response.errors[i][1][j]+'</div>');
-            }
-          }
-        }
-      }
-      if (response.alert) {
-        alert(response.alert)
-      }
-    }
-  }
-        
-      </script>
-      <script type="text/javascript">
-       jQuery(document).ready(function($) {
+      $(document).ready(function(){         
         $('a[rel*=facebox]').facebox()
       })
-      </script>
-      <script type="text/javascript">
-       jQuery(document).ready(function($) {
+      $(document).ready(function(){         
         $('a[rel*=close]').trigger('close.facebox')
       })
       </script>
diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml
index 45dc239..70fb66b 100644
--- a/wui/src/app/views/permission/new.rhtml
+++ b/wui/src/app/views/permission/new.rhtml
@@ -1,7 +1,9 @@
-<div class="dialog_title_small">
-  <div class="header">Add New User</div>
-  <div>Add a new user to  <%= @permission.pool.name %> pool.</div>
-</div>
+<%- content_for :title do -%>
+  Add New User
+<%- end -%>
+<%- content_for :description do -%>
+  Add a new user to  <%= @permission.pool.name %> pool.
+<%- end -%>
 
 <form method="POST" action="<%= url_for :action => 'create' %>" id="permission_form" >
 <div class="dialog_form">
@@ -9,28 +11,16 @@
 </div>
 <%= popup_footer("$('#permission_form').submit()", "Create User Permission") %>
 </form>
+
   <script type="text/javascript">
 $(function() {
     var permissionoptions = {
         target:        '<%= url_for :action => 'create' %>',   // target element to update
 	dataType:      'json',
-        success:       afterNewPermission  // post-submit callback
+        success:       afterPermission  // post-submit callback
     };
 
     // bind form using 'ajaxForm' 
     $('#permission_form').ajaxForm(permissionoptions); 
 });
-function afterNewPermission(response, status){
-    ajax_validation(response, status)
-    if (response.success) {
-      jQuery(document).trigger('close.facebox');
-      $("#users_grid").flexReload()
-    }
-}
 </script>
-
-<%- content_for :title do -%>
-<%= "Edit Permissions for #{@permission.pool.name}" %>
-<%- end -%>
-
-
diff --git a/wui/src/app/views/resources/new.rhtml b/wui/src/app/views/resources/new.rhtml
index 5897a5e..6d856f7 100644
--- a/wui/src/app/views/resources/new.rhtml
+++ b/wui/src/app/views/resources/new.rhtml
@@ -1,7 +1,9 @@
-<div class="dialog_title_small">
-  <div class="header">Add New Virtual Machine Pool</div>
-  <div>Add a new Virtual Machine Pool to the <%= @parent.name %> pool.</div>
-</div>
+<%- content_for :title do -%>
+  Add New Virtual Machine Pool
+<%- end -%>
+<%- content_for :description do -%>
+  Add a new Virtual Machine Pool to the <%= @parent.name %> pool.
+<%- end -%>
 
 <form method="POST" action="<%= url_for :action => 'create' %>" id="vm_pool_form" >
 <div class="dialog_form">
@@ -9,27 +11,16 @@
 </div>
 <%= popup_footer("$('#vm_pool_form').submit()", "Create Virtual Machine Pool") %>
 </form>
-  <script type="text/javascript">
+
+<script type="text/javascript">
 $(function() {
     var vmpooloptions = {
         target:        '<%= url_for :action => 'create' %>',   // target element to update
 	dataType:      'json',
-        success:       afterNewVmPool  // post-submit callback
+        success:       afterVmPool  // post-submit callback
     };
 
     // bind form using 'ajaxForm' 
     $('#vm_pool_form').ajaxForm(vmpooloptions); 
 });
-function afterNewVmPool(response, status){
-    ajax_validation(response, status)
-    if (response.success) {
-      jQuery(document).trigger('close.facebox');
-      $("#vmpools_grid").flexReload()
-    }
-}
 </script>
-
-<%- content_for :title do -%>
-<%= _("New VM Resource Pool") %>
-<%- end -%>
-
diff --git a/wui/src/app/views/resources/show.rhtml b/wui/src/app/views/resources/show.rhtml
index c42ebeb..ecf8fc6 100644
--- a/wui/src/app/views/resources/show.rhtml
+++ b/wui/src/app/views/resources/show.rhtml
@@ -1,87 +1,9 @@
 
-<div class="panel_header"></div>
-    <div id="data">
-      <div class="inside">
-
-        <%= error_messages_for 'vm_actions' %>
-
-          <div id="dataTableWrapper">
-
-          <div class="dataTable">
-              <div class="inside">
-
-                <div class="data-table-column">
-
-              <% form_tag( {:controller => 'resources', :action => 'vm_actions'}, {:name => "vm_actions", :method => "post"}) do -%>
-              <%= tag :input, { "type" => "hidden", "name" => "vm_actions[vm_resource_pool_id]", "value" => "@vm_resource_pool.id"}  %>
-              <%= tag :input, { "type" => "submit", "name" => "vm_actions[#{VmTask::ACTION_START_VM}]", "value" => "Start"}  %>
-              <%= tag :input, { "type" => "submit", "name" => "vm_actions[#{VmTask::ACTION_SHUTDOWN_VM}]", "value" => "Stop"}  %>
-              <select onchange="return confirm_and_submit(this)" name="vm_actions[other_actions]">
-                <option class="other">Other Actions</option>
-                <option></option>
-              <% for action in @action_values %>
-                <option value="<%= action[1]%>"><%= action[0]%></option>
-              <% end %>
-                <option>-------------------</option>
-                <option class="remove" value="destroy" onSelect="confirm('Are you sure?'">Destroy</option>
-              </select>
-
-              <br/>
-              <%= render :partial => '/layouts/alertbox' %>
-              <br/>
-
-              <%= render :partial => "/vm/list", :locals => { :vms => @vm_resource_pool.vms } %>
-              <% end -%>
-
-                </div>
-
-              </div> <!-- end #data-table.inside -->
-            </div> <!-- end #dataTable -->
-
-            <div class="data-section">
-              <div class="data-section-header"><strong>VM Resource Pool Quota</strong></div>
-              <div class="data-section-stats">Statistics Data</div>
-              <div class="data-section-table">
-                <div class="inside">
-
-                <table>
-                  <tr>
-                  <th></th>
-                  <td> in use / awaiting use / total allowed</td>
-                  </tr>
-                <% resources = @vm_resource_pool.full_resources %>
-                <% for item in resources[:labels] %>
-                <% total_limit = resources[:total][item[1]]
-                   total_limit = "unlimited" if total_limit.nil? %>
-                  <tr>
-                  <th><%= item[0]%>:</th>
-                  <td><%= resources[:allocated][:current][item[1]] %> / <%= resources[:allocated][:pending][item[1]] %> / <%= total_limit %>
-                      <%= item[2]%></td>
-                  </tr>
-                <% end %>
-                </table>
-
-                </div>
-              </div>
-            </div>
-
-
-          </div> <!-- end #dataTableWrapper -->
-
-      </div> <!-- end #data.inside -->
-      </div> <!-- end #data -->
-
-  </td>
   <td id="right">
     <div class="heading"> </div>
     <div class="tools">
     <h3>Actions</h3>
 
-  <%if @can_modify -%>
-  <div class="actions create">
-    <%= link_to_if @vm_resource_pool, 'Create New VM', {:controller => "vm", :action => 'new', :vm_resource_pool_id => @vm_resource_pool}, { :class => "create" } %>
-  </div>
-  <% end -%>
   <div class="actions">
     <%if @is_hwpool_admin -%>
     <%= link_to 'Edit VM Resource Pool', { :action => 'edit', :id => @vm_resource_pool }, { :class => "edit" } %>
diff --git a/wui/src/app/views/storage/_grid.rhtml b/wui/src/app/views/storage/_grid.rhtml
index 56fb621..feb855a 100644
--- a/wui/src/app/views/storage/_grid.rhtml
+++ b/wui/src/app/views/storage/_grid.rhtml
@@ -7,13 +7,14 @@
 	$("#<%= table_id %>").flexigrid
 	(
 	{
-	url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id %>',
+	url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id, :exclude_id => exclude_id %>',
 	dataType: 'json',
 	colModel : [
-		{display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
-		{display: 'Alias', name : 'display_name', width : 180, sortable : false, align: 'left'},
-	        {display: 'IP', name : 'ip_addr', width : 80, sortable : true, align: 'left'},
-		{display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'}
+		{display: '', width : 20, align: 'left', process: <%= table_id %>checkbox},
+		{display: 'Alias', width : 180, align: 'left'},
+		<%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %>
+	        {display: 'IP', name : 'ip_addr', width : 80, align: 'left'},
+		{display: 'Type', name : 'storage_pools.type', width : 80, align: 'left'}
 		],
 	sortname: "ip_addr",
 	sortorder: "asc",
diff --git a/wui/src/app/views/storage/addstorage.html.erb b/wui/src/app/views/storage/addstorage.html.erb
index a747502..e465d12 100644
--- a/wui/src/app/views/storage/addstorage.html.erb
+++ b/wui/src/app/views/storage/addstorage.html.erb
@@ -1,14 +1,17 @@
-<div class="dialog_title">
-	<div class="header">Add Storage</div>
-    <div>Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool.</div>
-</div>
+<%- content_for :title do -%>
+  Add Storage
+<%- end -%>
+<%- content_for :description do -%>
+  Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool.
+<%- end -%>
+
+<!-- we'll need this when we combine add/create for storage
 <div id="toolbar_nav">
 <ul>
     <li class="current" id="unassigned_tab"><a href="#" onClick = "show_unassigned()"><img style="vertical-align:middle;" src="" />  Unassigned Storage (<%= @unassigned %>)</a></li>
     <li id="assigned_tab"><a href="#" onClick = "show_assigned()"><img style="vertical-align:middle;" src="" />  Assigned Storage (<%= @assigned %>)</a></li>
 </ul>
 </div>
-<script type="text/javascript">
   function show_unassigned()
   {
       $("#assigned_tab").removeClass('current');
@@ -23,34 +26,17 @@
       $("#addstorage_unassigned_grid_div").hide()
       $("#addstorage_assigned_grid_div").show()
   }
-  function add_storage()
-  {
-    var assigned_selected= get_selected_checkboxes(document.addstorage_assigned_grid_form)
-    var unassigned_selected= get_selected_checkboxes(document.addstorage_unassigned_grid_form)
-    var storage = Array.concat(assigned_selected,unassigned_selected)
-    if (validate_selected(storage, "storage pool")) {
-      $.post('<%= url_for :controller => "hardware", :action => "add_storage", :id => @hardware_pool %>',
-             { storage_pool_ids: storage.toString() },
-              function(data,status){ 
-                jQuery(document).trigger('close.facebox');
-                $("#storage_grid").flexReload()
-		if (data.alert) {
-		  alert(data.alert);
-                }
-               }, 'json');
-    }
-  }
-</script>
+  $("#addstorage_assigned_grid_div").hide()
+-->
   <div class="panel_header"></div>
   <div class="dialog_body">
-       <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_unassigned_grid",
-           :hwpool_id => Pool.root.id, :on_select => "false" } %>
-       <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_assigned_grid",
-           :hwpool_id => nil, :on_select => "false" } %>
+       <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_grid",
+           :hwpool_id => nil, :exclude_id => @hardware_pool.id, 
+           :on_select => "false" } %>
   </div>
 </div>
-<script type="text/javascript">
-  $("#addstorage_assigned_grid_div").hide()
-</script>
-<%= popup_footer("add_storage()", "Add Selected Storage Pools") %>
+<%= popup_footer("add_storage('#{url_for :controller => 'hardware', 
+                                        :action => 'add_storage', 
+                                        :id => @hardware_pool}')", 
+                 "Add Selected Storage Pools") %>
 
diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml
index 6f88ce3..13dedb9 100644
--- a/wui/src/app/views/storage/new.rhtml
+++ b/wui/src/app/views/storage/new.rhtml
@@ -1,51 +1,47 @@
-<div class="dialog_title_small">
-  <div class="header">Add New Storage Pool</div>
-  <div>Add a new Storage Pool to this oVirt server.</div>
-</div>
+<%- content_for :title do -%>
+  Add New Storage Pool
+<%- end -%>
+<%- content_for :description do -%>
+  Add a new Storage Pool to this oVirt server.
+<%- end -%>
 
 <div class="dialog_form">
     <%= error_messages_for 'storage_pool' %>
-  <% form_tag  do %>
 
+  <% form_tag  do %>
     <!--[form:storage_pool]-->
     <%= hidden_field_tag 'hardware_pool_id', @hardware_pool.id %>
-    <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_details()"  %>
+    <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_storage_subform()"  %>
     <!--[eoform:storage_pool]-->
   <% end %>
 
   <div class="clear_row"></div>
   <div class="clear_row"></div>
 </div>
-<form method="POST" action="<%= url_for :action => 'create' %>" id="storage_pool_form" >
-<div class="dialog_form">
-  <div id="new_storage_pool"/>
 
-</div>
-<%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %>
+<form method="POST" action="<%= url_for :action => 'create' %>" id="storage_pool_form" >
+  <div class="dialog_form">
+    <div id="new_storage_pool"/>
+  </div>
+  <%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %>
 </form>
-  <script type="text/javascript">
-  function load_details()
+
+<script type="text/javascript">
+  function load_storage_subform()
   {
     $('#new_storage_pool').load('<%= url_for :controller => "storage", :action => "new2" %>',
                                 { hardware_pool_id: $('[name=hardware_pool_id]').val(), storage_type: $('[name=storage_type]').val()})
   }
-  load_details()
+  load_storage_subform()
 $(function() {
     var storageoptions = {
         target:        '<%= url_for :action => 'create' %>',   // target element to update
         //beforeSubmit:  showStorageRequest,  // pre-submit callback
 	dataType:      'json',
-        success:       afterNewStoragePool  // post-submit callback
+        success:       afterStoragePool  // post-submit callback
     };
 
     // bind form using 'ajaxForm' 
     $('#storage_pool_form').ajaxForm(storageoptions); 
 });
-function afterNewStoragePool(response, status){
-    ajax_validation(response, status)
-    if (response.success) {
-      jQuery(document).trigger('close.facebox');
-      $("#storage_grid").flexReload()
-    }
-}
-  </script>
+</script>
diff --git a/wui/src/app/views/vm/new.rhtml b/wui/src/app/views/vm/new.rhtml
index 60dbcd6..767f806 100644
--- a/wui/src/app/views/vm/new.rhtml
+++ b/wui/src/app/views/vm/new.rhtml
@@ -1,12 +1,9 @@
-<div id="window">
-
+<%- content_for :title do -%>
+  Add Virtual Machine
+<%- end -%>
+<%- content_for :description do -%>
+<%- end -%>
 
-  <!-- DIALOG  TITLE -->
-  <div class="dialog_title_small">
-    <div class="header">Add Virtual Machine</div>
-  </div>
-  
-  
   <!-- DIALOG  BODY -->
   <form method="POST" action="<%= url_for :action => 'create' %>" id="vm_form" >
   <div class="dialog_form">
@@ -15,9 +12,6 @@
   <!-- DIALOG  FOOTER -->
   <%= popup_footer("$('#vm_form').submit()", "Add Virtual Machine") %>
   </form>
-</div>
-
-
 
 <script type="text/javascript">
 $(function() {
@@ -25,21 +19,11 @@ $(function() {
         target:        '<%= url_for :action => 'create' %>',   // target element to update
         //beforeSubmit:  showStorageRequest,  // pre-submit callback
 	dataType:      'json',
-        success:       afterNewVm  // post-submit callback
+        success:       afterVm  // post-submit callback
     };
 
     // bind form using 'ajaxForm' 
     $('#vm_form').ajaxForm(vmoptions); 
 });
-function afterNewVm(response, status){
-    ajax_validation(response, status)
-    if (response.success) {
-      jQuery(document).trigger('close.facebox');
-      $("#vms_grid").flexReload()
-    }
-}
 </script>
 
-<%- content_for :title do -%>
-<%= "New Virtual Machine" %>
-<%- end -%>
diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js
new file mode 100644
index 0000000..675f20d
--- /dev/null
+++ b/wui/src/public/javascripts/ovirt.js
@@ -0,0 +1,138 @@
+// ovirt-specific javascript functions are defined here
+
+
+// helper functions for dialogs and action links
+
+
+// returns an array of selected values for flexigrid checkboxes
+function get_selected_checkboxes(obj_form)
+{
+  var selected_array = new Array()
+  var selected_index = 0
+  var checkboxes
+  if (obj_form.grid_checkbox) {
+    if (obj_form.grid_checkbox.length == undefined) {
+      checkboxes = [obj_form.grid_checkbox]
+    } else {
+      checkboxes = obj_form.grid_checkbox
+    }
+    for(var i=0; i < checkboxes.length; i++){
+    if(checkboxes[i].checked)
+      {
+        selected_array[selected_index]= checkboxes[i].value
+        selected_index++
+      }
+    }
+  }
+  return selected_array
+}
+
+
+// make sure that at least one item is selected to continue
+function validate_selected(selected_array, name)
+{
+  if (selected_array.length == 0) {
+    alert("Please select at least one " + name + "  to continue")
+    return false
+  } else {
+    return true
+  }
+}
+
+function add_hosts(url)
+{
+    hosts= get_selected_checkboxes(document.addhosts_grid_form)
+    if (validate_selected(hosts, "host")) {
+      $.post(url,
+             { resource_ids: hosts.toString() },
+              function(data,status){ 
+                jQuery(document).trigger('close.facebox');
+                $("#hosts_grid").flexReload()
+		if (data.alert) {
+		  alert(data.alert);
+                }
+               }, 'json');
+    }
+}
+function add_storage(url)
+{
+    storage= get_selected_checkboxes(document.addstorage_grid_form)
+    if (validate_selected(storage, "storage pool")) {
+      $.post(url,
+             { resource_ids: storage.toString() },
+              function(data,status){ 
+                jQuery(document).trigger('close.facebox');
+                $("#storage_grid").flexReload()
+		if (data.alert) {
+		  alert(data.alert);
+                }
+               }, 'json');
+    }
+}
+// deal with ajax form response, filling in validation messages where required.
+function ajax_validation(response, status)
+{
+  if (response.object) {
+    $(".fieldWithErrors").removeClass("fieldWithErrors");
+    $("div.errorExplanation").remove();
+    if (!response.success) {
+      for(i=0; i<response.errors.length; i++) { 
+        var element = $("div.form_field:has(#"+response.object + "_" + response.errors[i][0]+")");
+        if (element) {
+          element.addClass("fieldWithErrors");
+          for(j=0; j<response.errors[i][1].length; j++) { 
+            element.append('<div class="errorExplanation">'+response.errors[i][1][j]+'</div>');
+          }
+        }
+      }
+    }
+    if (response.alert) {
+      alert(response.alert)
+    }
+  }
+}
+
+// callback actions for dialog submissions
+function afterHwPool(response, status){
+    ajax_validation(response, status)
+    if (response.success) {
+      jQuery(document).trigger('close.facebox');
+      // FIXME do we need to reload the tree here
+
+      // this is for reloading the host/storage grid when 
+      // adding hosts/storage to a new HW pool
+      if (response.resource_type) {
+        $('#' + response.resource_type + '_grid').flexReload()
+      }
+      // do we have HW pools grid?
+      //$("#vmpools_grid").flexReload()
+    }
+}
+function afterVmPool(response, status){
+    ajax_validation(response, status)
+    if (response.success) {
+      jQuery(document).trigger('close.facebox');
+      $("#vmpools_grid").flexReload()
+    }
+}
+function afterStoragePool(response, status){
+    ajax_validation(response, status)
+    if (response.success) {
+      jQuery(document).trigger('close.facebox');
+      $("#storage_grid").flexReload()
+    }
+}
+function afterPermission(response, status){
+    ajax_validation(response, status)
+    if (response.success) {
+      jQuery(document).trigger('close.facebox');
+      $("#users_grid").flexReload()
+    }
+}
+function afterVm(response, status){
+    ajax_validation(response, status)
+    if (response.success) {
+      jQuery(document).trigger('close.facebox');
+      $("#vms_grid").flexReload()
+    }
+}
diff --git a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# b/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb#
deleted file mode 100644
index d430419..0000000
--- a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb#
+++ /dev/null
@@ -1,583 +0,0 @@
-module SymetrieCom
-  module Acts #:nodoc:
-    module NestedSet #:nodoc:
-      def self.included(base)
-        base.extend(ClassMethods)              
-      end
-      # This module provides an enhanced acts_as_nested_set mixin for ActiveRecord.
-      # Please see the README for background information, examples, and tips on usage.
-      module ClassMethods
-        # Configuration options are:
-        # * +parent_column+ - Column name for the parent/child foreign key (default: +parent_id+).
-        # * +left_column+ - Column name for the left index (default: +lft+). 
-        # * +right_column+ - Column name for the right index (default: +rgt+). NOTE: 
-        #   Don't use +left+ and +right+, since these are reserved database words.
-        # * +scope+ - Restricts what is to be considered a tree. Given a symbol, it'll attach "_id" 
-        #   (if it isn't there already) and use that as the foreign key restriction. It's also possible 
-        #   to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
-        #   Example: <tt>acts_as_nested_set :scope => 'tree_id = #{tree_id} AND completed = 0'</tt>
-        # * +text_column+ - Column name for the title field (optional). Used as default in the 
-        #   {your-class}_options_for_select helper method. If empty, will use the first string field 
-        #   of your model class.
-        def acts_as_nested_set(options = {})          
-          
-          options[:scope] = "#{options[:scope]}_id".intern if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
-          
-          write_inheritable_attribute(:acts_as_nested_set_options,
-             { :parent_column  => (options[:parent_column] || 'parent_id'),
-               :left_column    => (options[:left_column]   || 'lft'),
-               :right_column   => (options[:right_column]  || 'rgt'),
-               :scope          => (options[:scope] || '1 = 1'),
-               :text_column    => (options[:text_column] || columns.collect{|c| (c.type == :string) ? c.name : nil }.compact.first),
-               :class          => self # for single-table inheritance
-              } )
-          
-          class_inheritable_reader :acts_as_nested_set_options
-          
-          if acts_as_nested_set_options[:scope].is_a?(Symbol)
-            scope_condition_method = %(
-              def scope_condition
-                if #{acts_as_nested_set_options[:scope].to_s}.nil?
-                  "#{acts_as_nested_set_options[:scope].to_s} IS NULL"
-                else
-                  "#{acts_as_nested_set_options[:scope].to_s} = \#{#{acts_as_nested_set_options[:scope].to_s}}"
-                end
-              end
-            )
-          else
-            scope_condition_method = "def scope_condition() \"#{acts_as_nested_set_options[:scope]}\" end"
-          end
-          
-          # no bulk assignment
-          attr_protected  acts_as_nested_set_options[:left_column].intern,
-                          acts_as_nested_set_options[:right_column].intern,
-                          acts_as_nested_set_options[:parent_column].intern
-          # no assignment to structure fields
-          module_eval <<-"end_eval", __FILE__, __LINE__
-            def #{acts_as_nested_set_options[:left_column]}=(x)
-              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:left_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
-            end
-            def #{acts_as_nested_set_options[:right_column]}=(x)
-              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:right_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
-            end
-            def #{acts_as_nested_set_options[:parent_column]}=(x)
-              raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:parent_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
-            end
-            #{scope_condition_method}
-          end_eval
-          
-          
-          include SymetrieCom::Acts::NestedSet::InstanceMethods
-          extend SymetrieCom::Acts::NestedSet::ClassMethods
-          
-          # adds the helper for the class
-#          ActionView::Base.send(:define_method, "#{Inflector.underscore(self.class)}_options_for_select") { special=nil
-#              "#{acts_as_nested_set_options[:text_column]} || "#{self.class} id #{id}"
-#            }
-          
-        end
-        
-        
-        # Returns the single root for the class (or just the first root, if there are several).
-        # Deprecation note: the original acts_as_nested_set allowed roots to have parent_id = 0,
-        # so we currently do the same. This silliness will not be tolerated in future versions, however.
-        def root
-          acts_as_nested_set_options[:class].find(:first, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)")
-        end
-        
-        # Returns the roots and/or virtual roots of all trees. See the explanation of virtual roots in the README.
-        def roots
-          acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)", :order => "#{acts_as_nested_set_options[:left_column]}")
-        end
-        
-        # Checks the left/right indexes of all records, 
-        # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem.
-        def check_all
-          total = 0
-          transaction do
-            # if there are virtual roots, only call check_full_tree on the first, because it will check other virtual roots in that tree.
-            total = roots.inject(0) {|sum, r| sum + (r[r.left_col_name] == 1 ? r.check_full_tree : 0 )}
-            raise ActiveRecord::ActiveRecordError, "Scope problems or nodes without a valid root" unless acts_as_nested_set_options[:class].count == total
-          end
-          return total
-        end
-        
-        # Re-calculate the left/right values of all nodes. Can be used to convert ordinary trees into nested sets.
-        def renumber_all
-          scopes = []
-          # only call it once for each scope_condition (if the scope conditions are messed up, this will obviously cause problems)
-          roots.each do |r|
-            r.renumber_full_tree unless scopes.include?(r.scope_condition)
-            scopes << r.scope_condition
-          end
-        end
-        
-        # Returns an SQL fragment that matches _items_ *and* all of their descendants, for use in a WHERE clause.
-        # You can pass it a single object, a single ID, or an array of objects and/or IDs.
-        #   # if a.lft = 2, a.rgt = 7, b.lft = 12 and b.rgt = 13
-        #   Set.sql_for([a,b]) # returns "((lft BETWEEN 2 AND 7) OR (lft BETWEEN 12 AND 13))"
-        # Returns "1 != 1" if passed no items. If you need to exclude items, just use "NOT (#{sql_for(items)})".
-        # Note that if you have multiple trees, it is up to you to apply your scope condition.
-        def sql_for(items)
-          items = [items] unless items.is_a?(Array)
-          # get objects for IDs
-          items.collect! {|s| s.is_a?(acts_as_nested_set_options[:class]) ? s : acts_as_nested_set_options[:class].find(s)}.uniq
-          items.reject! {|e| e.new_record?} # exclude unsaved items, since they don't have left/right values yet
-          
-          return "1 != 1" if items.empty? # PostgreSQL didn't like '0', and SQLite3 didn't like 'FALSE'
-          items.map! {|e| "(#{acts_as_nested_set_options[:left_column]} BETWEEN #{e[acts_as_nested_set_options[:left_column]]} AND #{e[acts_as_nested_set_options[:right_column]]})" }
-          "(#{items.join(' OR ')})"
-        end
-        
-      end
-
-      # This module provides instance methods for an enhanced acts_as_nested_set mixin. Please see the README for background information, examples, and tips on usage.
-      module InstanceMethods
-        # convenience methods to make the code more readable
-        def left_col_name()#:nodoc:
-          acts_as_nested_set_options[:left_column]
-        end
-        def right_col_name()#:nodoc:
-          acts_as_nested_set_options[:right_column]
-        end
-        def parent_col_name()#:nodoc:
-          acts_as_nested_set_options[:parent_column]
-        end
-        alias parent_column parent_col_name#:nodoc: Deprecated
-        def base_set_class()#:nodoc:
-          acts_as_nested_set_options[:class] # for single-table inheritance
-        end
-        
-        # On creation, automatically add the new node to the right of all existing nodes in this tree.
-        def before_create # already protected by a transaction
-          maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0
-          self[left_col_name] = maxright+1
-          self[right_col_name] = maxright+2
-        end
-        
-        # On destruction, delete all children and shift the lft/rgt values back to the left so the counts still work.
-        def before_destroy # already protected by a transaction
-          return if self[right_col_name].nil? || self[left_col_name].nil?
-          self.reload # in case a concurrent move has altered the indexes
-          dif = self[right_col_name] - self[left_col_name] + 1
-          base_set_class.delete_all( "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})" )
-          base_set_class.update_all("#{left_col_name} = CASE \
-                                      WHEN #{left_col_name} > #{self[right_col_name]} THEN (#{left_col_name} - #{dif}) \
-                                      ELSE #{left_col_name} END, \
-                                 #{right_col_name} = CASE \
-                                      WHEN #{right_col_name} > #{self[right_col_name]} THEN (#{right_col_name} - #{dif} ) \
-                                      ELSE #{right_col_name} END",
-                                 scope_condition)
-        end
-        
-        # By default, records are compared and sorted using the left column.
-        def <=>(x)
-          self[left_col_name] <=> x[left_col_name]
-        end
-        
-        # Deprecated. Returns true if this is a root node.
-        def root?
-          parent_id = self[parent_col_name]
-          (parent_id == 0 || parent_id.nil?) && self[right_col_name] && self[left_col_name] && (self[right_col_name] > self[left_col_name])
-        end
-        
-        # Deprecated. Returns true if this is a child node
-        def child?                          
-          parent_id = self[parent_col_name]
-          !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name])
-        end
-        
-        # Deprecated. Returns true if we have no idea what this is
-        def unknown?
-          !root? && !child?
-        end
-        
-        # Returns this record's root ancestor.
-        def root
-          # the BETWEEN clause is needed to ensure we get the right virtual root, if using those
-          base_set_class.find(:first, :conditions => "#{scope_condition} \
-            AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0) AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})")
-        end
-        
-        # Returns the root or virtual roots of this record's tree (a tree cannot have more than one real root). See the explanation of virtual roots in the README.
-        def roots
-          base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0)", :order => "#{left_col_name}")
-        end
-        
-        # Returns this record's parent.
-        def parent
-          base_set_class.find(self[parent_col_name]) if self[parent_col_name]
-        end
-        
-        # Returns an array of all parents, starting with the root.
-        def ancestors
-          self_and_ancestors - [self]
-        end
-        
-        # Returns an array of all parents plus self, starting with the root.
-        def self_and_ancestors
-          base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})", :order => left_col_name )
-        end
-        
-        # Returns all the children of this node's parent, except self.
-        def siblings
-          self_and_siblings - [self]
-        end
-        
-        # Returns all the children of this node's parent, including self.
-        def self_and_siblings
-          if self[parent_col_name].nil? || self[parent_col_name].zero?
-            [self]
-          else
-            base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self[parent_col_name]}", :order => left_col_name)
-          end
-        end
-        
-        # Returns the level of this object in the tree, root level being 0.
-        def level
-          return 0 if self[parent_col_name].nil?
-          base_set_class.count(:conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})") - 1
-        end
-        
-        # Returns the number of nested children of this object.
-        def all_children_count
-          return (self[right_col_name] - self[left_col_name] - 1)/2
-        end
-        
-        # Returns itself and all nested children.
-        # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants.
-        def full_set(special=nil)
-          if special && special[:exclude]
-            exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) "
-          elsif new_record? || self[right_col_name] - self[left_col_name] == 1
-            return [self]
-          endas
-          base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name)
-        end
-        
-        # Returns all children and nested children.
-        # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants.
-        def all_children(special=nil)
-          full_set(special) - [self]
-        end
-        
-        # Returns this record's immediate children.
-        def children
-          base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name)
-        end
-        
-        # Deprecated
-        alias direct_children children
-        
-        # Returns this record's terminal children (nodes without children).
-        def leaves
-          base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}", :order => left_col_name)
-        end
-        
-        # Returns the count of this record's terminal children (nodes without children).
-        def leaves_count
-          base_set_class.count(:conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}")
-        end
-        
-        # Checks the left/right indexes of one node and all descendants. 
-        # Throws ActiveRecord::ActiveRecordError if it finds a problem.
-        def check_subtree
-          transaction do
-            self.reload
-            check # this method is implemented via #check, so that we don't generate lots of unnecessary nested transactions
-          end
-        end
-        
-        # Checks the left/right indexes of the entire tree that this node belongs to, 
-        # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem.
-        # This method is needed because check_subtree alone cannot find gaps between virtual roots, orphaned nodes or endless loops.
-        def check_full_tree
-          total_nodes = 0
-          transaction do
-            # virtual roots make this method more complex than it otherwise would be
-            n = 1
-            roots.each do |r| 
-              raise ActiveRecord::ActiveRecordError, "Gaps between roots in the tree containing record ##{r.id}" if r[left_col_name] != n
-              r.check_subtree
-              n = r[right_col_name] + 1
-            end
-            total_nodes = roots.inject(0) {|sum, r| sum + r.all_children_count + 1 }
-            unless base_set_class.count(:conditions => "#{scope_condition}") == total_nodes
-              raise ActiveRecord::ActiveRecordError, "Orphaned nodes or endless loops in the tree containing record ##{self.id}"
-            end
-          end
-          return total_nodes
-        end
-        
-        # Re-calculate the left/right values of all nodes in this record's tree. Can be used to convert an ordinary tree into a nested set.
-        def renumber_full_tree
-          indexes = []
-          n = 1
-          transaction do
-            for r in roots # because we may have virtual roots
-              n = r.calc_numbers(n, indexes)
-            end
-            for i in indexes
-              base_set_class.update_all("#{left_col_name} = #{i[:lft]}, #{right_col_name} = #{i[:rgt]}", "#{self.class.primary_key} = #{i[:id]}")
-            end
-          end
-          ## reload?
-        end
-        
-        # Deprecated. Adds a child to this object in the tree.  If this object hasn't been initialized,
-        # it gets set up as a root node.
-        #
-        # This method exists only for compatibility and will be removed in future versions.
-        def add_child(child)
-          transaction do
-            self.reload; child.reload # for compatibility with old version
-            # the old version allows records with nil values for lft and rgt
-            unless self[left_col_name] && self[right_col_name]
-              if child[left_col_name] || child[right_col_name]
-                raise ActiveRecord::ActiveRecordError, "If parent lft or rgt are nil, you can't add a child with non-nil lft or rgt"
-              end
-              base_set_class.update_all("#{left_col_name} = CASE \
-                                          WHEN id = #{self.id} \
-                                            THEN 1 \
-                                          WHEN id = #{child.id} \
-                                            THEN 3 \
-                                          ELSE #{left_col_name} END, \
-                                     #{right_col_name} = CASE \
-                                          WHEN id = #{self.id} \
-                                            THEN 2 \
-                                          WHEN id = #{child.id} \
-                                            THEN 4 \
-                                         ELSE #{right_col_name} END",
-                                      scope_condition)
-              self.reload; child.reload
-            end
-            unless child[left_col_name] && child[right_col_name]
-              maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0
-              base_set_class.update_all("#{left_col_name} = CASE \
-                                          WHEN id = #{child.id} \
-                                            THEN #{maxright + 1} \
-                                          ELSE #{left_col_name} END, \
-                                      #{right_col_name} = CASE \
-                                          WHEN id = #{child.id} \
-                                            THEN #{maxright + 2} \
-                                          ELSE #{right_col_name} END",
-                                      scope_condition)
-              child.reload
-            end
-            
-            child.move_to_child_of(self)
-            # self.reload ## even though move_to calls target.reload, at least one object in the tests was not reloading (near the end of test_common_usage)
-          end
-        # self.reload
-        # child.reload
-        #
-        # if child.root?
-        #   raise ActiveRecord::ActiveRecordError, "Adding sub-tree isn\'t currently supported"
-        # else
-        #   if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) )
-        #     # Looks like we're now the root node!  Woo
-        #     self[left_col_name] = 1
-        #     self[right_col_name] = 4
-        #     
-        #     # What do to do about validation?
-        #     return nil unless self.save
-        #     
-        #     child[parent_col_name] = self.id
-        #     child[left_col_name] = 2
-        #     child[right_col_name]= 3
-        #     return child.save
-        #   else
-        #     # OK, we need to add and shift everything else to the right
-        #     child[parent_col_name] = self.id
-        #     right_bound = self[right_col_name]
-        #     child[left_col_name] = right_bound
-        #     child[right_col_name] = right_bound + 1
-        #     self[right_col_name] += 2
-        #     self.class.transaction {
-        #       self.class.update_all( "#{left_col_name} = (#{left_col_name} + 2)",  "#{scope_condition} AND #{left_col_name} >= #{right_bound}" )
-        #       self.class.update_all( "#{right_col_name} = (#{right_col_name} + 2)",  "#{scope_condition} AND #{right_col_name} >= #{right_bound}" )
-        #       self.save
-        #       child.save
-        #     }
-        #   end
-        # end
-        end
-        
-        # Move this node to the left of _target_ (you can pass an object or just an id).
-        # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem.
-        def move_to_left_of(target)
-          self.move_to target, :left
-        end
-        
-        # Move this node to the right of _target_ (you can pass an object or just an id).
-        # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem.
-        def move_to_right_of(target)
-          self.move_to target, :right
-        end
-        
-        # Make this node a child of _target_ (you can pass an object or just an id).
-        # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem.
-        def move_to_child_of(target)
-          self.move_to target, :child
-        end
-        
-        protected
-        def move_to(target, position) #:nodoc:
-          raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if new_record?
-          raise ActiveRecord::ActiveRecordError, "You cannot move a node if left or right is nil" unless self[left_col_name] && self[right_col_name]
-          
-          transaction do
-            self.reload # the lft/rgt values could be stale (target is reloaded below)
-            if target.is_a?(base_set_class)
-              target.reload # could be stale
-            else
-              target = base_set_class.find(target) # load object if we were given an ID
-            end
-            
-            if (target[left_col_name] >= self[left_col_name]) && (target[right_col_name] <= self[right_col_name])
-              raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree."
-            end
-            
-            # prevent moves between different trees
-            if target.scope_condition != scope_condition
-              raise ActiveRecord::ActiveRecordError, "Scope conditions do not match. Is the target in the same tree?"
-            end
-            
-            # the move: we just need to define two adjoining segments of the left/right index and swap their positions
-            bound = case position
-              when :child then target[right_col_name]
-              when :left  then target[left_col_name]
-              when :right then target[right_col_name] + 1
-              else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left or :right ('#{position}' received)."
-            end
-            
-            if bound > self[right_col_name]
-              bound = bound - 1
-              other_bound = self[right_col_name] + 1
-            else
-              other_bound = self[left_col_name] - 1
-            end
-            
-            return if bound == self[right_col_name] || bound == self[left_col_name] # there would be no change, and other_bound is now wrong anyway
-            
-            # we have defined the boundaries of two non-overlapping intervals, 
-            # so sorting puts both the intervals and their boundaries in order
-            a, b, c, d = [self[left_col_name], self[right_col_name], bound, other_bound].sort
-            
-            # change nil to NULL for new parent
-            if position == :child
-              new_parent = target.id
-            else
-              new_parent = target[parent_col_name].nil? ? 'NULL' : target[parent_col_name]
-            end
-            
-            base_set_class.update_all("\
-              #{left_col_name} = CASE \
-                WHEN #{left_col_name} BETWEEN #{a} AND #{b} THEN #{left_col_name} + #{d - b} \
-                WHEN #{left_col_name} BETWEEN #{c} AND #{d} THEN #{left_col_name} + #{a - c} \
-                ELSE #{left_col_name} END, \
-              #{right_col_name} = CASE \
-                WHEN #{right_col_name} BETWEEN #{a} AND #{b} THEN #{right_col_name} + #{d - b} \
-                WHEN #{right_col_name} BETWEEN #{c} AND #{d} THEN #{right_col_name} + #{a - c} \
-                ELSE #{right_col_name} END, \
-              #{parent_col_name} = CASE \
-                WHEN #{self.class.primary_key} = #{self.id} THEN #{new_parent} \
-                ELSE #{parent_col_name} END",
-              scope_condition)
-            self.reload
-            target.reload
-          end
-        end
-        
-        def check #:nodoc:
-          # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt
-          ## i don't use the scope condition here, because it shouldn't be needed
-          my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}",
-            :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}")
-          
-          if my_children.empty?
-            unless self[left_col_name] && self[right_col_name]
-              raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} or #{left_col_name} is blank"
-            end
-            unless self[right_col_name] - self[left_col_name] == 1
-              raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{left_col_name}"
-            end
-          else
-            n = self[left_col_name]
-            for c in (my_children) # the children come back ordered by lft
-              unless c[left_col_name] && c[right_col_name]
-                raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{right_col_name} or #{left_col_name} is blank"
-              end
-              unless c[left_col_name] == n + 1
-                raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{left_col_name} should be 1 greater than #{n}"
-              end
-              c.check
-              n = c[right_col_name]
-            end
-            unless self[right_col_name] == n + 1
-              raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{n}"
-            end
-          end
-        end
-        
-        # used by the renumbering methods
-        def calc_numbers(n, indexes) #:nodoc:
-          my_lft = n
-          # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt
-          ## i don't use the scope condition here, because it shouldn't be needed
-          my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}",
-            :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}")
-          if my_children.empty?
-            my_rgt = (n += 1)
-          else
-            for c in (my_children)
-              n = c.calc_numbers(n + 1, indexes)
-            end
-            my_rgt = (n += 1)
-          end
-          indexes << {:id => self.id, :lft => my_lft, :rgt => my_rgt} unless self[left_col_name] == my_lft && self[right_col_name] == my_rgt
-          return n
-        end
-        
-        
-        
-        # The following code is my crude method of making things concurrency-safe.
-        # Basically, we need to ensure that whenever a record is saved, the lft/rgt
-        # values are _not_ written to the database, because if any changes to the tree
-        # structure occurrred since the object was loaded, the lft/rgt values could 
-        # be out of date and corrupt the indexes. 
-        # I hope that someone with a little more ruby-foo can look at this and come
-        # up with a more elegant solution.
-        private
-          # override ActiveRecord to prevent lft/rgt values from being saved (can corrupt indexes under concurrent usage)
-          def update #:nodoc:
-            connection.update(
-              "UPDATE #{self.class.table_name} " +
-              "SET #{quoted_comma_pair_list(connection, special_attributes_with_quotes(false))} " +
-              "WHERE #{self.class.primary_key} = #{quote_value(id)}",
-              "#{self.class.name} Update"
-            )
-          end
-
-          # exclude the lft/rgt columns from update statements
-          def special_attributes_with_quotes(include_primary_key = true) #:nodoc:
-            attributes.inject({}) do |quoted, (name, value)|
-              if column = column_for_attribute(name)
-                quoted[name] = quote_value(value, column) unless (!include_primary_key && column.primary) || [acts_as_nested_set_options[:left_column], acts_as_nested_set_options[:right_column]].include?(column.name)
-              end
-              quoted
-            end
-          end
-
-          # i couldn't figure out how to call attributes_with_quotes without cutting and pasting this private method in.  :(
-          # Quote strings appropriately for SQL statements.
-          def quote_value(value, column = nil) #:nodoc:
-            self.class.connection.quote(value, column)
-          end
-
-      end
-    end
-  end
-end
-
-
diff --git a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb
index 43b46ca..ed5d3e3 100644
--- a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb
+++ b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb
@@ -246,24 +246,33 @@ module SymetrieCom
         
         # Returns itself and all nested children.
         # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants.
-        def full_set(special=nil)
-          if special && special[:exclude]
-            exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) "
+        # in addition to the standard find opts
+        def full_set(find_opts={})
+          exclude = find_opts.delete(:exclude)
+          if exclude
+            exclude_str = " AND NOT (#{base_set_class.sql_for(exclude)}) "
           elsif new_record? || self[right_col_name] - self[left_col_name] == 1
             return [self]
           end
-          base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name)
+          opts = merge_incoming_opts({:conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", 
+                                       :order => left_col_name},
+                                     find_opts)
+          base_set_class.find(:all, opts)
         end
         
         # Returns all children and nested children.
         # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants.
-        def all_children(special=nil)
-          full_set(special) - [self]
+        # in addition to the standard find opts
+        def all_children(find_opts=nil)
+          full_set(find_opts) - [self]
         end
         
         # Returns this record's immediate children.
-        def children
-          base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name)
+        def children(find_opts={})
+          opts = merge_incoming_opts({:conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", 
+                                      :order => left_col_name},
+                                     find_opts)
+          base_set_class.find(:all, opts)
         end
         
         # Deprecated
@@ -575,6 +584,14 @@ module SymetrieCom
             self.class.connection.quote(value, column)
           end
 
+          # accept incoming opts to allow filtering of results.
+          # So far only tested in limited use cases encountered in oVirt devel.
+          def merge_incoming_opts(set_opts, incoming_opts)
+            new_conditions = incoming_opts.delete(:conditions)
+            set_opts[:conditions] = "(#{set_opts[:conditions]}) AND (#{new_conditions})" if new_conditions
+            set_opts.merge(incoming_opts)
+          end
+
       end
     end
   end
-- 
1.5.4.1


--------------040805000303080804070604--




More information about the ovirt-devel mailing list