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

发布于 2024-11-27 19:05:48 字数 724 浏览 1 评论 0原文

我有一个这样的类结构:

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 对象。此请求的 Content-Type application/json

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

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

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

ActiveRecord::AssociationTypeMismatch (Child (#2198796760) 预期,得到 ActiveSupport::HashWithIn DifferentAccess(#2158000780)):

有人知道发生了什么事吗?

I have a class structure like this:

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

In my mobile app (IOS + RestKit), I submit a HTTP POST request to create a new Parent object. This request has Content-Type application/json

The request looks like this on the wire:

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

When Rails receives it, and tries to save it, I get the error:

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

Anyone know what's going on?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

执着的年纪 2024-12-04 19:05:48

为了扩展 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

可以(并且可能应该)将其移至对象模型上的 before_create 过滤器中。

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

To expand one what Sameer said, you need to send child_attributes instead of child. This means you can't use the same mapping for pulling from the server and then pushing to it.

In RestKit you can specify a custom serialization that's different from the original object mapping. Here's an example that posts to a rails app, where 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]];

Note that it's also important to remove the ID attributes when posting - that gave me no end of trouble, since it doesn't seem like it should matter in a post, but it throws rails off.

For what it's worth, I also had issues parsing the nested objects with rails, and had to change my controller to look like this:

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

That could (and probably should) be moved into a before_create filter on the Object model.

I hope that helps in some way.

极致的悲 2024-12-04 19:05:48

使用“child_attributes”代替参数哈希中的“child”。

Instead of "child" in your params hash, use "child_attributes".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文