Как избежать сохранения пустых записей в форме вложенных рельсов - программирование
Подтвердить что ты не робот

Как избежать сохранения пустых записей в форме вложенных рельсов

Я использую nested_form gem для моего отношения AddressBook. Когда пользователь вычеркивает значение существующего Addr, я хочу удалить его Addr вместо сохранения с помощью пробела value

class Person < ActiveRecord::Base
  has_many :addrs, dependent: :destroy
  attr_accessible :name, :addrs_attributes
  accepts_nested_attributes_for :addrs, reject_if: :addr_blank, allow_destroy: true

  def addr_blank(a)
    valid? && a[:id].blank? && a[:value].blank? 
  end

class Addr < ActiveRecord::Base
  belongs_to :person
  attr_accessible :kind, :label, :value, :person_id

Мой метод :reject_if работает хорошо, но он не дает мне все, что мне нужно

  • valid? хранит мои пустые Addrs через проверку.
  • a[:id].blank? избегает отклонений, когда пользователь выполняет пропуски и существующую запись

Теперь мне нужно удалить (а не сохранить) существующий Addr, когда пользователь закроет value. Кроме того, я подвергаю людей и Addrs через RESTful API. Я вижу два возможных варианта:

  • Запустите процесс хеша params, чтобы добавить магический параметр _destroy=1. IOW, эмулирует активность пользователя при нажатии кнопки удаления.
  • Инкапсулируйте это внутри модели Addr, так что обновление с пустой value эффективно считается удалением.

Основываясь на совете, вот как я его реализовал:

people_controller.rb

def update
  @person = Person.find(params[:id])
  @person.destroy_blank_addrs(params[:person])
  respond_to do |format|
  ...

person.rb

def destroy_blank_addrs(person_params)
  if valid? && person_params[:addrs_attributes]
    person_params[:addrs_attributes].each do |addr_params_array|
      addr_params= addr_params_array[1] 
      addr_params[:_destroy] = '1' if !addr_params[:id].blank? && addr_params[:value].blank? 
    end
  end
end
4b9b3361

Ответ 1

Третьей альтернативой было бы добавить обратный вызов before_save для Person, который удалит все пустые адреса. Эта идея имеет некоторые достоинства, но я, вероятно, не поеду с ней.

Из двух представленных вами параметров я не буду перерабатывать параметры. Это сработает, но это слишком большая работа. Кроме того, код контроллера будет немного беспорядочным, и я твердо верю в очень тонкий контроллер.

Самый простой вариант - в моей голове - удалить пустые адреса после сохранения. Вы можете добавить Person#remove_blank_addresses(), а затем вызвать его при успешном сохранении. Вам не нужно передавать параметры - он может просто перебирать адреса и удалять пустые. У него есть недостаток в создании пустых адресов, а затем их уничтожении, но вам все равно понадобится для обновления людей.

Если мы говорим о самом чистом решении (на мой взгляд), я бы представил третий класс, который обрабатывал бы всю эту логику и имел бы делегировать ему контроллер. Контроллер будет достаточно прост, чтобы протестировать изолированно, а затем вы можете написать модельную спецификацию, которая проверяет все подробные детали. Это немного больше работы, и я не могу думать о хорошем имени прямо сейчас (PersonUpdater?), Но это может быть идея, о которой стоит подумать.

Ответ 2

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  :reject_if => proc { |att| att[:name].blank? && attr[:description].blank? }

Ответ 3

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: -> { |attr| [name, description].any? &:blank? }

Ответ 4

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: :all_blank