вложенное массовое присваивание с монгоидом - PullRequest
2 голосов
/ 28 апреля 2011

с отношением has_one / own_to, я не могу обновить вложенные записи с помощью массового назначения.

Модель:

class ProductVariation
  include Mongoid::Document
  has_one                       :shipping_profile,  :inverse_of => :variation
  field                         :quantity
  attr_accessible               :shipping_profile_attributes
  accepts_nested_attributes_for :shipping_profile
end

class ShippingProfile
  include Mongoid::Document
  belongs_to       :variation, :class_name => "ProductVariation"
  field            :weight,    :type => Float
  attr_accessible  :weight
end

Контроллер:

@variation = ProductVariation.find(params[:id])
@variation.update_attributes(params[:product_variation])

почтовый запрос:

Parameters:{
  "product_variation"=>{
    "quantity"=>"13",
    "shipping_profile_attributes"=>{
      "weight"=>"66",
      "id"=>"4dae758ce1607c1d18000074"
    }
  },
  "id"=>"4dae758ce1607c1d18000073"
}

Монго запрос:

MONGODB app_development['product_variations'].update({"_id"=>BSON::ObjectId('4dae758ce1607c1d18000073')}, {"$set"=>{"quantity"=>13, "updated_at"=>2011-04-28 06:59:17 UTC}})

и я даже не получаю запрос на обновление монго, если product_variation не имеет каких-либо измененных атрибутов ... что мне здесь не хватает?

1 Ответ

2 голосов
/ 28 мая 2012

Рабочие модели и модульный тест приведены ниже, чтобы продемонстрировать, что вы можете обновить дочерние параметры и сохранить их в базе данных через родительский элемент, как это предусмотрено с помощью accepts_nested_attributes_for и опции автосохранение: true дляотношения.

В документации Mongoid говорится, что при попытке установить защищенное поле с помощью массового присвоения возникнет ошибка, но она устарела.Вместо этого сообщения, подобные следующим, печатаются в файл журнала.

WARNING: Can't mass-assign protected attributes: id

Вам следует внимательно искать эти сообщения в соответствующем файле журнала, чтобы диагностировать вашу проблему.Это поможет вам заметить, что у вас есть вложенное поле id для профиля доставки в ваших параметрах, и это, похоже, также приводит к отклонению веса, возможно, вместе со всеми дочерними параметрами.После добавления «attr_accessible: id» в модель ShippingProfile вес теперь назначается.Вам также необходимо добавить «attr_accessible: количество» (а я добавил: id для модульного теста) в модель ProductVariation

Следующая проблема заключается в том, что вам нужно добавить «autosave: true», добавленное к отношению has_oneчтобы потомок обновлялся через родителя, в противном случае вам нужно будет сохранить его вручную.

Возможно, вас заинтересует sanitize_for_mass_assignment , который можно использовать для отмывания идентификаторов.

include ActiveModel::MassAssignmentSecurity

p sanitize_for_mass_assignment(params['product_variation'], :default)

Юнит-тест должен прояснить весь предмет, я оставлю работу контроллера за вами.Надеюсь, что это понятно и помогает.

class ProductVariation
  include Mongoid::Document
  has_one                       :shipping_profile, :inverse_of => :variation, autosave: true
  field                         :quantity
  accepts_nested_attributes_for :shipping_profile
  attr_accessible               :id
  attr_accessible               :quantity
  attr_accessible               :shipping_profile_attributes
end

class ShippingProfile
  include Mongoid::Document
  belongs_to       :variation, :class_name => "ProductVariation"
  field            :weight,    :type => Float
  attr_accessible  :id
  attr_accessible  :weight
end

test / unit / product_varitation_test.rb

require 'test_helper'

class ProductVariationTest < ActiveSupport::TestCase
  def setup
    ProductVariation.delete_all
    ShippingProfile.delete_all
  end

  test "mass assignment" do
    params = {
      "product_variation"=>{
        "quantity"=>"13",
        "shipping_profile_attributes"=>{
          "weight"=>"66",
          "id"=>"4dae758ce1607c1d18000074"
        }
      },
      "id"=>"4dae758ce1607c1d18000073"
    }

    product_variation_id = params['id']
    shipping_profile_id = params['product_variation']['shipping_profile_attributes']['id']
    product_variation = ProductVariation.create("id" => product_variation_id)
    shipping_profile = ShippingProfile.create("id" => shipping_profile_id)
    product_variation.shipping_profile = shipping_profile
    assert_equal(1, ProductVariation.count)
    assert_equal(1, ShippingProfile.count)

    product_variation.update_attributes(params['product_variation'])
    assert_equal('13', ProductVariation.find(product_variation_id)['quantity'])
    assert_equal(66.0, ShippingProfile.find(shipping_profile_id)['weight'])
    p ProductVariation.find(product_variation_id)
    p ShippingProfile.find(shipping_profile_id)
  end
end

тестовый вывод

Run options: --name=test_mass_assignment

# Running tests:

#<ProductVariation _id: 4dae758ce1607c1d18000073, _type: nil, quantity: "13">
#<ShippingProfile _id: 4dae758ce1607c1d18000074, _type: nil, variation_id: BSON::ObjectId('4dae758ce1607c1d18000073'), weight: 66.0>
.

Finished tests in 0.014682s, 68.1106 tests/s, 272.4424 assertions/s.

1 tests, 4 assertions, 0 failures, 0 errors, 0 skips

Process finished with exit code 0
...