2014-12-12 2 views
0

у меня есть Person модели и Business модели оба из которых have_many contacts, as:contactableRails вложенной модель форма ошибки обновляемых дети

Я не уверен, как правильно обновить вложенную модель, но то, что я сделал это следующим образом :

мой PARAMS хэш следующим образом:

{"person"=> 
    {"name"=>"updated name", 
    ....... 
    "contacts_attributes"=> 
    {"0"=>{"contact_type"=>"web", "contact_sub_type"=>"main", "address"=>"http:www.example.com/changed", "id"=>"2"}, 
    "1"=>{"contact_type"=>"twitter", "contact_sub_type"=>"main", "address"=>"changedtwerson", "id"=>"4"}, 
"2"=> {contact_type: "facebook", contact_sub_type: "main" , id: "3" }, 
"3"=> {contact_type: "email", contact_sub_type: "main",id: "1" } 
}}, 
    "submit"=>"save", 
    "id"=>"1", 
    "controller"=>"persons", 
    "action"=>"update"} 

в рамках модели у меня уже есть 3 person.contacts для Contact.contact_type "Сети", "Facebook" и "Twitter" с contact_sub_type, соответствующий введенным выше входам.

В Контактной модели у меня есть validates_uniqueness_of :contact_type, scope: [:contact_sub_type, :contactable_id ]

Потому что, если адрес является пустым, я не хочу, чтобы загрузить контакт с человеком/объектом бизнеса я включил в методе, чтобы установить сильный код Params в destroy_all записи, которые не имеют адрес:

def person_params 
    contact_list = params[:person][:contacts_attributes].delete_if { |key, value| value[:address].blank? } if params[:person].present? && params[:person][:contacts_attributes].present? 
    cl_ary = [] 
    contact_list.values.each { |v| cl_ary << v[:id] } 
    @person.contacts.where.not(id: cl_ary).destroy_all if @person && @person.contacts 

    params.require(:person).permit(:name, ...... 
        contacts_attributes: [:id, :address, :contact_type, :contact_sub_type]) unless params[:person].nil? 
end 

Когда я называю @person = Person.find (ID: Params [: ID]) @ person.update person_params

я получаю значение ложь возвращается и @person недействительна как :contact_type=>["has already been taken"]

после обновления @person.contacts дает мне следующее (что мне следует пройти уникальную проверку)

[#<Contact id: 4, contact_type: "twitter", contact_sub_type: "main", address: "changedtwerson", contactable_id: 1, contactable_type: "Person", created_at: "2014-12-12 10:09:15", updated_at: "2014-12-12 10:09:24">, #<Contact id: 2, contact_type: "web", contact_sub_type: "main", address: "http:www.example.com/changed", contactable_id: 1, contactable_type: "Person", created_at: "2014-12-12 10:09:15", updated_at: "2014-12-12 10:09:24">] 

поэтому у меня есть 2 вопроса:

  1. У меня есть действительный подход здесь, я пропустил что-нибудь и есть лучший способ?
  2. Как я могу взглянуть дальше на проверку и выяснить, почему проверка не выполняется, когда она выглядит ОК визуально?

ответ

1

Ответ на вопрос 1: это недействительный подход.

Рефакторинг Person класс, добавив:

accepts_nested_attributes_for :contacts, :allow_destroy => true, :reject_if => proc {|attrs| attrs[:address].blank?}

и от метода person_params REMOVE:

contact_list = params[:person][:contacts_attributes].delete_if { |key, value| value[:address].blank? } if params[:person].present? && params[:person][:contacts_attributes].present? cl_ary = [] contact_list.values.each { |v| cl_ary << v[:id] } @person.contacts.where.not(id: cl_ary).destroy_all if @person && @person.contacts

изменение также валидатор:

validates_uniqueness_of :contact_type, scope: [:contact_sub_type, :contactable_id, :contactable_type] 

, чтобы предотвратить условия для участия в гонке за человека/бизнеса.

Refactor update действие на:

@person = Person.find(id: params[:id]) 
@person.attributes = person_params 
@person.contacts.select {|x| x.address.blank?}.each(&:mark_for_destruction) 
@person.save 
+0

Спасибо, вы просто бить меня к этому изменению. Однако он позволяет только удалять контакты из хэша params, которые имеют пустой адрес. Person_params возвращает хэш только с контактами с адресом.Однако, если существующий человек имеет 4 контакта и 1 указан в хеше (после отклонения), 3 следует удалить из db, и это то, что пытается выполнить вторая часть (destroy_all). Путем простого отклонения адресов пробелов 1 обновляется, а остальные 3 остаются неизмененными, а не удаляются. – Richbits

+0

В моем документе неверные данные не должны быть сохранены в БД. Проверка модели должна предотвращать такой сценарий. Если у вас уже есть поврежденные данные, чем удалить их вручную. – olhor

+0

Абсолютно согласен. Все контакты в базе данных имеют адрес, но когда это отображается в форме, пользователь может удалить адрес, а затем он будет отправлен как недопустимая запись (это потому, что у меня есть скрытые поля в форме, классифицирующей поле (id/contact_type/sub_type) ... Я обновлю этот вопрос, чтобы отразить это. Это пустые записи, которые reject_if удалит, но если они сохранены в обновлении базы данных, они автоматически не удалят их, поэтому действие destroy_all. – Richbits

Смежные вопросы