Ticket #30 (new defect)

Opened 2 years ago

Last modified 2 years ago

nested_set_options_for_select raises exception when passed an Array

Reported by: rails Assigned to: jcm
Priority: major Milestone:
Component: plugin Version: trunk
Keywords: Cc:

Description

If you want to pass an Array of roots to nested_set_options_for_select, it will raise a "Not a nested set model !" exception because Array doesn't directly respond_to acts_as_nested_set_options (even though its contents might).

The issue is that lines 102 and 111 of better_nested_set_helper.rb r34 try to call acts_as_nested_set_options() directly on the class_or_item parameter, when they might need to call it on the first element if class_or_item is an Array.

Change History

04/28/07 23:40:28 changed by rails

Here is a suggested fix with a couple of other tweaks, including better handling of the case when no options are passed, and adjusting the indentation when not starting at the root of the tree.

@@ -95,33 +95,40 @@
         # find class
         if class_or_item.is_a? Class
           first_item = class_or_item.roots
+          nested_set_class = class_or_item
+        elsif class_or_item.is_a? Array
+          first_item = class_or_item
+          nested_set_class = first_item.empty? ? nil : first_item[0].class
         else
           first_item = class_or_item
+          nested_set_class = first_item.class
         end       
         return [] if first_item.nil?
-        raise 'Not a nested set model !' unless class_or_item.respond_to?(:acts_as_nested_set_options)
+        raise 'Not a nested set model !' unless nested_set_class.respond_to?(:acts_as_nested_set_options)
         
         # exclude some items and all their children
         if options.is_a? Hash
           text_column = options[:text_column]
           options.delete_if { |key, value| key != :exclude }
         else
-          options = nil
+          options = {}
         end
-        text_column ||= class_or_item.acts_as_nested_set_options[:text_column]
+        text_column ||= nested_set_class.acts_as_nested_set_options[:text_column]
         
         if first_item.is_a?(Array)
           tree = first_item.collect{|i| i.full_set(options)}.flatten
+          first_item_level = first_item.empty? ? 0 : first_item[0].level
         else
           tree = first_item.full_set(options)
+          first_item_level = first_item.level
         end
         if block_given?
           tree.map{|item| [yield(item), item.id] }
-        else  
-          tree.map{|item| [ "#{'··' * item.level}#{item[text_column]}", item.id]}
+        else
+          tree.map{|item| [ "#{'··' * (item.level - first_item_level)}#{item[text_column]}", item.id]}