DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Multi-part Parameter Extractor

08.27.2006
| 4463 views |
  • submit to reddit
        For those times when you want to get a date object out of the multi-part parameters without having to do a mass assignment to a model object. I extracted this code directly from AR so I think it should be pretty solid but I have not tested it so your mileage may vary.

Take the following and place it into your application helper or whatever helper you'd like. To use it you simply pass in an instance of the object on which the multi-part parameter exists. This is so that the type to instantiate can be reflected from the column information. Then you specify the attribute name of the parameter you're looking to create from the next parameter which is the hash containing the multi-part parameter value.

example:
for a form containing dude[birth_date] you'd call the method like this:

extract_date(@the_dude, 'birth_date', params[:dude])

    def extract_date(parent_object, param_name, atts)
      atts.stringify_keys!

      multi_parameter_attributes = []
      atts.each do |k, v|
        multi_parameter_attributes << [ k, v ] if k.include?(param_name+"(")
      end
      
      attributes = { }

      for pair in multi_parameter_attributes
        multiparameter_name, value = pair
        attribute_name = multiparameter_name.split("(").first
        attributes[attribute_name] = [] unless attributes.include?(attribute_name)

        unless value.empty?
          attributes[attribute_name] <<
            [ find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value) ]
        end
      end

      attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
      errors = []
      result = nil
      attributes.each do |name, values|  
        klass = (parent_object.class.reflect_on_aggregation(name.to_sym) || parent_object.column_for_attribute(name)).klass
        result = Time == klass ? klass.local(*values) : klass.new(*values)
      end

      return result
    end
    
    def find_parameter_position(multiparameter_name)
      multiparameter_name.scan(/\(([0-9]*).*\)/).first.first
    end

    def type_cast_attribute_value(multiparameter_name, value)
      multiparameter_name =~ /\([0-9]*([a-z])\)/ ? value.send("to_" + $1) : value
    end