具有application / json内容类型的HTTP POST中的嵌套模型

时间:2011-08-05 02:34:24

标签: ruby-on-rails restkit

我有这样的类结构:

class Parent < ActiveRecord::Base
    has_one :child
    accepts_nested_attributes_for :child
end

...

class Child < ActiveRecord::Base
    belongs_to :parent
    validates :text, :presence => true
end

在我的移动应用(IOS + RestKit)中,我提交HTTP POST请求以创建新的Parent对象。此请求包含内容类型application/json

请求在线上看起来像这样:

{"parent":{"field1":"value1","child":{"text":"textvalue"},"duration":100}}

当Rails收到它并尝试保存它时,我收到错误:

ActiveRecord::AssociationTypeMismatch (Child(#2198796760) expected, got ActiveSupport::HashWithIndifferentAccess(#2158000780)):

任何人都知道发生了什么事?

2 个答案:

答案 0 :(得分:3)

要扩展Sameer所说的内容,您需要发送child_attributes而不是child。这意味着您不能使用相同的映射从服务器拉出然后推送到它。

在RestKit中,您可以指定与原始对象映射不同的自定义序列化。这是一个发布到rails应用程序的示例,其中Object has_many Images

//Map Images
RKManagedObjectMapping* imageMapping = [RKManagedObjectMapping mappingForEntityWithName:@"Image"];
imageMapping.setNilForMissingRelationships = YES;
imageMapping.primaryKeyAttribute = @"imageId";
[imageMapping mapKeyPathsToAttributes:@"id", @"imageId", @"is_thumbnail", @"isThumbnail", @"image_caption", @"imageCaption", @"image_data", @"imageData", nil];

//Serialize Images
RKManagedObjectMapping* imageSerialization = (RKManagedObjectMapping*)[imageMapping inverseMapping];
imageSerialization.rootKeyPath = @"image";
[imageSerialization removeMappingForKeyPath:@"imageId"];

//Map Objects
RKManagedObjectMapping* objectMapping = [RKManagedObjectMapping mappingForEntityWithName:@"Object"];
objectMapping.setNilForMissingRelationships = YES;
objectMapping.primaryKeyAttribute = @"objectId";
[objectMapping mapKeyPath:@"id" toAttribute:@"objectId"];
[objectMapping mapRelationship:@"images" withMapping:imageMapping];

//Serialize Objects
RKManagedObjectMapping* objectSerialization = (RKManagedObjectMapping*)[objectMapping inverseMapping];
objectSerialization.rootKeyPath = @"object";
[objectSerialization removeMappingForKeyPath:@"images"];
[objectSerialization removeMappingForKeyPath:@"objectId"];
[objectSerialization mapKeyPath:@"images" toRelationship:@"images_attributes" withMapping:imageSerialization];

[objectManager.mappingProvider setMapping:objectMapping forKeyPath:@"object"];
[objectManager.mappingProvider setSerializationMapping:objectSerialization forClass:[Object class]];

请注意,在发布时删除ID属性也很重要 - 这给我带来了麻烦,因为它看起来似乎不应该在帖子中发挥作用,但它会抛弃轨道。

对于它的价值,我也遇到了使用rails解析嵌套对象的问题,并且必须将我的控制器更改为如下所示:

def create
    images = params[:object].delete("images_attributes");
    @object = Object.new(params[:object])

    result = @object.save

    if images
      images.each do |image|
        image.delete(:id)
        @object.images.create(image)
      end
    end

    respond_to do |format|
      if result
        format.html { redirect_to(@object, :notice => 'Object was successfully created.') }
        format.json  { render :json => @object, :status => :created, :location => @object }
      else
        format.html { render :action => "new" }
        format.json  { render :json => @object.errors, :status => :unprocessable_entity }
      end
    end
  end

可以(也可能应该)移动到Object模型的before_create过滤器中。

我希望在某种程度上有所帮助。

答案 1 :(得分:2)

使用“child_attributes”来代替“params”中的“child”。