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

时间:2012-07-14 23:59:18

标签: ruby-on-rails nested-forms

我正在使用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方法效果很好,但它并没有给我所需的一切

  1. valid?通过验证保留我的空白地址
  2. a[:id].blank?在用户空白和现有记录时避免拒绝
  3. 现在,当用户空白Addr时,我需要删除(而不是保存)现有的value。另外,我通过RESTful API公开了Persons和Addrs。我看到两种可能的选择:

    1. 后处理params哈希以添加神奇的_destroy=1参数。 IOW,模拟按下删除按钮的用户活动。
    2. 将其封装在Addr模型中,以便将带有空白value的更新实际视为删除。
    3. 基于这里的建议是我如何实现它:

      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
      

4 个答案:

答案 0 :(得分:15)

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

答案 1 :(得分:8)

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

答案 2 :(得分:5)

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

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

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

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

答案 3 :(得分:2)

accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: :all_blank
相关问题