Rails nested_attributes
(в частности, для этого случая ваш rubic_attributes
хэш) означает, что вы изменяете связанную запись (записи), а не саму запись.Поскольку item_id
является атрибутом модели материала, а не связанной модели Rubic
, то вложенный атрибут Hash не сможет обновить это значение (если только связанная с ним запись не уничтожена через _destroy
, из которых, похоже, Railsавтоматически обновлять material.rubric_id
до nil
).
Но поскольку вы не хотите уничтожать связанную запись, а просто обновляете material.rubric_id
до nil
через material.update(rubric_attributes: {...})
Hash и вам это не нужночтобы использовать «обычный способ» простого выполнения material.update(rubric_id: nil)
, тогда вы можете сделать обходной путь, подобный приведенному ниже, который все еще использует rubric_attributes
:
class Material < ApplicationRecord
belongs_to :rubric, optional: true
accepts_nested_attributes_for :rubric, allow_destroy: true
end
class Rubric < ApplicationRecord
has_many :materials, dependent: :nullify
accepts_nested_attributes_for :materials
end
Использование:
rubric = Rubric.create!
material = Material.create!(rubric: rubric)
material.update!(
rubric_attributes: {
id: material.rubric.id,
materials_attributes: {
id: material.id,
rubric_id: nil # or `rubric: nil`
}
}
)
puts material.rubric_id
# => 1
# not sure why `material` needs to be reloaded. Rails `inverse_of` seems to not work on "nested" nested_attributes
material.reload
puts material.rubric_id
# => nil
puts Rubric.exists?(id: 1)
# => true
# now you've updated material.rubric_id to nil, but not destroying the Rubric record
Внимание!Если эти вложенные атрибуты будут использоваться в контроллере, в целях безопасности не забудьте разрешить только params.permit(rubric_attributes: [materials_attributes: [:rubric_id]])
... или любые другие поля, которые вы считаете белыми.