Вложенная модель в HTTP POST с типом содержимого application / json - PullRequest
1 голос
/ 05 августа 2011

У меня есть такая структура классов:

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 ]

3 голосов
/ 05 августа 2011

Чтобы расширить сказанное Самиром, вам нужно отправить 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 при публикации - это не доставило мне никаких проблем, так как это не кажетсякак будто это должно иметь значение в посте, но это сбрасывает рельсы.

Для чего бы это ни стоило, у меня также были проблемы с анализом вложенных объектов с помощью рельсов, и мне пришлось изменить свой контроллер, чтобы он выглядел так:

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 в модели объектов.

Надеюсь, это поможет каким-то образом.

2 голосов
/ 05 августа 2011

Вместо "child" в хэше params, используйте "child_attributes".

...