Skip to content

Instantly share code, notes, and snippets.

@watson
Created October 29, 2010 17:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save watson/653925 to your computer and use it in GitHub Desktop.
Save watson/653925 to your computer and use it in GitHub Desktop.
A way to accept the same XML input as model.to_xml generates as output (see http://stackoverflow.com/questions/4052677/rails-nested-resources-input-vs-output-format-inconsistency for details)
class ApplicationController < ActionController::Base
private
def fix_nested_attribute_structure(data = nil, model = nil)
unless data
# guess data based on current controller
data = params[self.class.to_s.sub('Controller', '').singularize.underscore.to_sym]
end
unless model
# guess model based on current controller
model = self.class.to_s.sub('Controller', '').singularize.constantize
end
# iterate over the nested attribute keys for the given model
model.nested_attributes_options.keys.each do |key|
# skip if current data-set doesn't contain this key
next unless data.has_key? key
# When recieving the XML all nested attributes are "doubble-nested".
# We need to remove this doubble-nesting and also ensure that the
# content is wrapped inside an array (e.g. if the orignal XML only
# contained a single sub-node, the XML->Hash conversion would not
# have done this)
raise "More than one sub-key found inside a nested attribute key" if data[key].keys.size > 1
sub_key = data[key].keys[0]
data[key] = [ data[key].delete(sub_key) ].flatten
# Recursively fix nested attributes
fix_nested_attribute_structure data[key], eval(key.to_s.classify)
# Renamed the nested attribute name by appending '_attributes' to
# the key-name
data["#{key.to_s}_attributes".to_sym] = data.delete(key)
end
end
end
class CompaniesController < ApplicationController
before_filter :fix_nested_attribute_structure, :only => [:create, :update]
...
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment