Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3196: multiple_associations_for_forms.patch

File multiple_associations_for_forms.patch, 13.1 kB (added by benanderson.us@gmail.com, 3 years ago)
  • actionpack/lib/action_view/helpers/form_helper.rb

    old new  
    212212        @object_name, @method_name = object_name.to_s, method_name.to_s 
    213213        @template_object, @local_binding = template_object, local_binding 
    214214        @object = object 
    215         if @object_name.sub!(/\[\]$/,"") 
    216           @auto_index = @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}").id_before_type_cast 
     215        on = @object_name.clone 
     216        while on.sub!(/\[\]/,"") 
     217          @auto_indexes = Array.new if @auto_indexes == nil  
     218          on = Regexp.last_match.pre_match 
     219          poppers = @template_object.instance_variable_get("@#{on}").id_before_type_cast 
     220          @auto_indexes << poppers 
     221          @object_names = Array.new if @object_names == nil 
     222          @object_names << on 
     223          @object_name = on.clone 
     224          on = Regexp.last_match.post_match 
    217225        end 
    218226      end 
    219227 
     
    236244        options["value"]    = tag_value 
    237245        options["checked"]  = "checked" if value.to_s == tag_value.to_s 
    238246        pretty_tag_value    = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase 
    239         options["id"]       = @auto_index ?              
    240           "#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" : 
    241           "#{@object_name}_#{@method_name}_#{pretty_tag_value}" 
     247        if @auto_indexes 
     248          options["id"] = String.new 
     249          @auto_indexes.each_with_index do |ai, i| 
     250            options["id"] << "#{@object_names[i]}_#{ai}_" 
     251          end 
     252          options["id"] << "#{@method_name}_#{pretty_tag_value}" 
     253        else 
     254          options["id"]     = "#{@object_name}_#{@method_name}_#{pretty_tag_value}" 
     255        end 
     256        if false 
     257          options["id"]       = @auto_index ?              
     258            "#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" : 
     259            "#{@object_name}_#{@method_name}_#{pretty_tag_value}" 
     260        end 
    242261        add_default_name_and_id(options) 
    243262        tag("input", options) 
    244263      end 
     
    300319      end 
    301320       
    302321      def object 
     322        #puts "@object_name: #@object_name" 
    303323        @object || @template_object.instance_variable_get("@#{@object_name}") 
    304324      end 
    305325 
    306326      def value 
    307327        unless object.nil? 
    308           object.send(@method_name) 
     328          o = object.send(@method_name) 
     329          #puts "o: #{o}" 
     330          o 
    309331        end 
    310332      end 
    311333 
     
    323345            options["name"] ||= tag_name_with_index(options["index"]) 
    324346            options["id"]   ||= tag_id_with_index(options["index"]) 
    325347            options.delete("index") 
    326           elsif @auto_index 
    327             options["name"] ||= tag_name_with_index(@auto_index) 
    328             options["id"]   ||= tag_id_with_index(@auto_index) 
     348          elsif @auto_indexes 
     349            options["name"] ||= tag_name_with_index 
     350            options["id"]   ||= tag_id_with_index 
    329351          else 
    330352            options["name"] ||= tag_name 
    331353            options["id"]   ||= tag_id 
     
    336358          "#{@object_name}[#{@method_name}]" 
    337359        end 
    338360 
    339         def tag_name_with_index(index) 
    340           "#{@object_name}[#{index}][#{@method_name}]" 
     361        def tag_name_with_index 
     362          name = String.new 
     363          @auto_indexes.each_with_index do |ai, i| 
     364            if i == 0 
     365              name << "#{@object_names[i]}[#{ai}]" 
     366            else 
     367              name << "[#{@object_names[i]}][#{ai}]" 
     368            end 
     369          end 
     370          name << "[#{@method_name}]" 
    341371        end 
    342372 
    343373        def tag_id 
    344374          "#{@object_name}_#{@method_name}" 
    345375        end 
    346376 
    347         def tag_id_with_index(index) 
    348           "#{@object_name}_#{index}_#{@method_name}" 
     377        def tag_id_with_index 
     378          #"#{@object_name}_#{index}_#{@method_name}" 
     379          id = String.new 
     380          @auto_indexes.each_with_index do |ai, i| 
     381            id << "#{@object_names[i]}_#{ai}_" 
     382          end 
     383          id << "#{@method_name}" 
    349384        end 
    350385    end 
    351386 
  • actionpack/test/template/form_helper_test.rb

    old new  
    1414      alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast) 
    1515      alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast) 
    1616    end 
     17    Comment = Struct.new("Comment", :title, :author_name, :body, :secret, :written_on, :cost) 
     18    Comment.class_eval do 
     19      alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast) 
     20      alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast) 
     21      alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast) 
     22    end 
    1723  end 
    1824 
    1925  def setup 
     
    2935    @post.secret      = 1 
    3036    @post.written_on  = Date.new(2004, 6, 15) 
    3137 
     38    @comment = Comment.new 
     39    def @comment.errors() Class.new{ def on(field) field == "author_name" end }.new end 
     40 
     41    def @comment.id; 456; end 
     42    def @comment.id_before_type_cast; 456; end 
     43 
     44    @comment.title       = "Goodbye World" 
     45    @comment.author_name = "" 
     46    @comment.body        = "And here comes another hill..." 
     47    @comment.secret      = 1 
     48    @comment.written_on  = Date.new(1980, 6, 5) 
     49 
    3250    @controller = Class.new do 
    3351      def url_for(options, *parameters_for_method_reference) 
    3452        "http://www.example.com" 
     
    176194 
    177195  def test_auto_index 
    178196    pid = @post.id 
     197    cid = @comment.id 
    179198    assert_dom_equal( 
    180199      "<input id=\"post_#{pid}_title\" name=\"post[#{pid}][title]\" size=\"30\" type=\"text\" value=\"Hello World\" />", text_field("post[]","title") 
    181200    ) 
    182201    assert_dom_equal( 
     202      "<input id=\"post_#{pid}_comment_#{cid}_title\" name=\"post[#{pid}][comment][#{cid}][title]\" size=\"30\" type=\"text\" value=\"Goodbye World\" />", text_field("post[]comment[]","title") 
     203    ) 
     204    assert_dom_equal( 
    183205      "<textarea cols=\"40\" id=\"post_#{pid}_body\" name=\"post[#{pid}][body]\" rows=\"20\">Back to the hill and over it again!</textarea>", 
    184206      text_area("post[]", "body") 
    185207    ) 
    186208    assert_dom_equal( 
     209      "<textarea cols=\"40\" id=\"post_#{pid}_comment_#{cid}_body\" name=\"post[#{pid}][comment][#{cid}][body]\" rows=\"20\">And here comes another hill...</textarea>", 
     210      text_area("post[]comment[]", "body") 
     211    ) 
     212    assert_dom_equal( 
    187213      "<input checked=\"checked\" id=\"post_#{pid}_secret\" name=\"post[#{pid}][secret]\" type=\"checkbox\" value=\"1\" /><input name=\"post[#{pid}][secret]\" type=\"hidden\" value=\"0\" />", 
    188214      check_box("post[]", "secret") 
    189215    ) 
     216    assert_dom_equal( 
     217      "<input checked=\"checked\" id=\"post_#{pid}_comment_#{cid}_secret\" name=\"post[#{pid}][comment][#{cid}][secret]\" type=\"checkbox\" value=\"1\" /><input name=\"post[#{pid}][comment][#{cid}][secret]\" type=\"hidden\" value=\"0\" />", 
     218      check_box("post[]comment[]", "secret") 
     219    ) 
    190220   assert_dom_equal( 
    191221"<input checked=\"checked\" id=\"post_#{pid}_title_hello_world\" name=\"post[#{pid}][title]\" type=\"radio\" value=\"Hello World\" />", 
    192222      radio_button("post[]", "title", "Hello World") 
    193223    ) 
     224   assert_dom_equal( 
     225"<input checked=\"checked\" id=\"post_#{pid}_comment_#{cid}_title_goodbye_world\" name=\"post[#{pid}][comment][#{cid}][title]\" type=\"radio\" value=\"Goodbye World\" />", 
     226      radio_button("post[]comment[]", "title", "Goodbye World") 
     227    ) 
    194228    assert_dom_equal("<input id=\"post_#{pid}_title_goodbye_world\" name=\"post[#{pid}][title]\" type=\"radio\" value=\"Goodbye World\" />", 
    195229      radio_button("post[]", "title", "Goodbye World") 
    196230    ) 
     231    assert_dom_equal("<input id=\"post_#{pid}_comment_#{cid}_title_so_long_world\" name=\"post[#{pid}][comment][#{cid}][title]\" type=\"radio\" value=\"So Long World\" />", 
     232      radio_button("post[]comment[]", "title", "So Long World") 
     233    ) 
    197234  end 
    198235 
    199236  def test_form_for 
  • activerecord/lib/active_record/base.rb

    old new  
    243243    # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+. 
    244244    cattr_accessor :logger 
    245245 
     246    def self.load_hash(_h, key_in=nil) 
     247      if key_in == nil 
     248        key_in = self.to_s 
     249      end 
     250      h = _h.clone 
     251      if 0 == h.keys[0].to_i 
     252        h = Hash.new 
     253        h["1"] = _h 
     254      end 
     255      a = Array.new 
     256      h.each do |k, v| 
     257        c = eval("#{Inflector.camelize(key_in)}") 
     258        id = nil 
     259        pk = c.primary_key 
     260        id = v[pk] 
     261        if id 
     262          r = c.find(id) 
     263        else 
     264          r = c.new 
     265        end 
     266        a << r 
     267        v.each do |k2, v2| 
     268          if v2.is_a?(Hash) 
     269            m = Inflector.pluralize(k2) 
     270            children = self.load_hash(v2, k2) 
     271            if !children.is_a?(Array) 
     272              ch = Array.new 
     273              ch << children 
     274              children = ch 
     275            end 
     276            if false 
     277              childClass = children[0].class 
     278              children.each do |c| 
     279                if !origChildren.include?(c) 
     280                  origChildren << children 
     281                end 
     282              end 
     283            end 
     284            origChildren = r.send("#{m}") 
     285            children.each do |c| 
     286              if !c.id 
     287                origChildren.push(c) 
     288              end 
     289            end 
     290          else 
     291            if k2 != pk 
     292              r.send("#{k2}=", v2) 
     293            end 
     294          end 
     295        end 
     296        r.save if id 
     297      end 
     298      if a.length == 0 
     299        return nil 
     300      else 
     301        return a 
     302      end 
     303    end 
     304 
     305    # Returns the connection currently associated with the class. This can 
     306    # also be used to "borrow" the connection to do database work unrelated 
     307    # to any of the specific Active Records. 
     308    def self.connection 
     309      retrieve_connection 
     310    end 
     311 
     312    # Returns the connection currently associated with the class. This can 
     313    # also be used to "borrow" the connection to do database work that isn't 
     314    # easily done without going straight to SQL. 
     315    def connection 
     316      self.class.connection 
     317    end 
     318 
    246319    def self.inherited(child) #:nodoc: 
    247320      @@subclasses[self] ||= [] 
    248321      @@subclasses[self] << child 
  • activerecord/test/load_hash_test.rb

    old new  
     1require 'abstract_unit' 
     2require 'fixtures/Developer' 
     3require 'fixtures/Project' 
     4require 'logger' 
     5 
     6class LoadHashTest < Test::Unit::TestCase 
     7  fixtures :developers, :projects 
     8   
     9  cattr_accessor :logger 
     10 
     11  def setup 
     12    @david_before = Developer.find(1) 
     13    @active_record_before = Project.find(1) 
     14    @count_projects_before = @david_before.projects.length 
     15    @count_developers_before = Developer.count() 
     16    @h1 = { "1" =>  
     17            { "id" => "1", 
     18              "name" => "update dev", 
     19              "project" => 
     20                { "2" => 
     21                  { "id" => "1", 
     22                    "name" => "cocoon", 
     23                    "type" => ""}, 
     24                  "3" => 
     25                  { "name" => "myfaces", 
     26                    "type" => "" } 
     27                } 
     28            }, 
     29            "4" => 
     30            { "name" => "new dev", 
     31              "project" => 
     32                { "5" => 
     33                  { "name" => "struts", 
     34                    "type" => "" }, 
     35                  "6" => 
     36                  { "name" => "tomcat", 
     37                    "type" => "" } 
     38                } 
     39            } 
     40          } 
     41    @h2 = { "name" => "new dev", 
     42            "project" => 
     43              { "2" => 
     44                { "name" => "daddy", 
     45                  "type" => ""}, 
     46                "3" => 
     47                { "name" => "baby", 
     48                  "type" => "" } 
     49              } 
     50          } 
     51    @devs1 = Developer.load_hash(@h1) 
     52    @dev1 = Developer.load_hash(@h2) 
     53  end 
     54 
     55  def test_project_update 
     56    @devs1.each do |d| 
     57      d.projects.each do |p| 
     58        p.save 
     59      end 
     60    end 
     61    active_record_after = Project.find(1) 
     62    assert_not_equal(@active_record_before.name, active_record_after.name) 
     63  end 
     64 
     65  def test_correct_classes 
     66    assert_kind_of(Array, @devs1) 
     67    assert_kind_of(Array, @dev1) 
     68    @devs1.each do |d| 
     69      assert_kind_of(Developer, d) 
     70      d.projects.each do |p| 
     71        assert_kind_of(Project, p) 
     72      end 
     73    end 
     74  end 
     75 
     76  def test_dev_update 
     77    @devs1.each do |d| 
     78      d.save 
     79    end 
     80    david_after = Developer.find(1) 
     81    assert_not_equal(@david_before.name, david_after.name) 
     82    assert_equal(@count_projects_before + 1, david_after.projects.length) 
     83    developers_after = Developer.count() 
     84    assert_not_equal(@count_developers_before, developers_after) 
     85  end 
     86 
     87  def test_dev_insert 
     88  end 
     89 
     90end 
     91 
     92LoadHashTest.logger = ActiveRecord::Base.logger