如何避免在嵌套的rails表单上保存空记录

Chr*_*eck 18 ruby-on-rails nested-forms

我正在使用nested_form宝石作为我的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
Run Code Online (Sandbox Code Playgroud)

我的:reject_if方法运作良好,但它没有给我我需要的一切

  1. valid? 通过验证保持我的空白Addrs
  2. a[:id].blank? 当用户空白和现有记录时避免拒绝

现在,Addr当用户空白时,我需要删除(而不是保存)现有的value.另外,我通过RESTful API公开了Persons和Addrs.我看到两种可能的选择:

  1. 发布处理params哈希以添加神奇的_destroy=1参数.IOW,模拟按下删除按钮的用户活动.
  2. 将其封装在Addr模型中,以便将带有空白的更新value有效地视为删除.

基于这里的建议是我如何实现它:

people_controller.rb

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

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
Run Code Online (Sandbox Code Playgroud)

Shi*_*ouk 15

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  :reject_if => proc { |att| att[:name].blank? && attr[:description].blank? }
Run Code Online (Sandbox Code Playgroud)


Kyl*_*cot 8

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: -> { |attr| [name, description].any? &:blank? }
Run Code Online (Sandbox Code Playgroud)


Ste*_*nev 5

第三种方法是before_save在Person 上添加一个回调,删除所有空白的地址.这个想法有一些优点,但我可能不会接受它.

在你提出的两个选项中,我不会对params进行后期处理.它会成功,但这是太多的工作.此外,控制器代码将变得有点混乱,我坚信一个非常苗条的控制器.

在我的脑海中,最简单的选择是在保存后删除空白地址.您可以添加Person#remove_blank_addresses(),然后在成功保存时调用它.您不需要传递参数 - 它可以迭代地址并删除空白地址.它的缺点是创建空地址然后销毁它们,但无论如何你都需要更新人员.

如果我们谈论最干净的解决方案(在我看来),我会介绍一个第三类,它将处理所有逻辑并让控制器委托给它.控制器很容易单独测试,然后你可以编写一个模型规范来检查所有细节.这是一个更多的工作,我现在想不出一个好名字(PersonUpdater?),但它可能是一个值得思考的想法.