Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/54.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何避免在嵌套rails窗体上保存空记录_Ruby On Rails_Nested Forms - Fatal编程技术网

Ruby on rails 如何避免在嵌套rails窗体上保存空记录

Ruby on rails 如何避免在嵌套rails窗体上保存空记录,ruby-on-rails,nested-forms,Ruby On Rails,Nested Forms,我正在使用嵌套的\u表单gem来处理我的通讯簿关系。当用户清空现有Addr的值时,我希望删除该Addr,而不是使用空白值保存 class Person < ActiveRecord::Base has_many :addrs, dependent: :destroy attr_accessible :name, :addrs_attributes accepts_nested_attributes_for :addrs, reject_if: :addr_blank, allo

我正在使用
嵌套的\u表单
gem来处理我的
通讯簿
关系。当用户清空现有
Addr
的值时,我希望删除该
Addr
,而不是使用空白
值保存

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
person.rb

def update
  @person = Person.find(params[:id])
  @person.destroy_blank_addrs(params[:person])
  respond_to do |format|
  ...
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

第三种选择是在Person上的_save
回调之前添加一个
,该回调将删除所有空白地址。这个想法有一些优点,但我可能不会同意

在您提供的两个选项中,我不会对参数进行后期处理。这会成功的,但工作量太大了。此外,到控制器的代码将变得有点混乱,我坚信一个非常苗条的控制器

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


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

在这两个选项中,使用选项1。你不想看到像“如果X字段的值为空,那么就删除记录”这样的“魔法”。我用你建议的解决方案更新了这个问题。@Zabba,18个月后我正在重构这段代码,你是对的。我想把这个值作为一个“神奇的”
destroy\u blank\u addrs
来消隐,但这个想法已经过时了。我还认为,任何涉及直接修改
params
数组的解决方案都是不好的做法。任何后处理都应该在
assign_attributes
之后,但在
save
之前完成。谢谢您深思熟虑的回复,Stefan。第三类是最干净的解决方案,但太费劲了。将可用于某个异步进程(即使只是一瞬间)的记录放入数据库的想法似乎是错误的。另一个想法是在JS前端管理它。消隐只是按下删除按钮的另一种方式。然后,消隐永远不会进入我的RESTAPI。在这种情况下,我会在控制器中使用此代码。这是一个有点棘手的测试和不知何故看起来混乱在我的信念什么应该在控制器,但它应该是最干净的解决方案在您的情况下。谢谢,我去控制器的方法,因为我觉得它更简单,它增加了功能,我的API,消费者可以删除添加空白的价值。如果您更新您的答案,我将接受。现在我正在重构此代码,将其移动到
ServiceObject
(如您所建议的)是最佳解决方案。我把它命名为
percontracker
,因为它还负责更新
活动
日志。有关更多信息,请参阅“非常简明”。我包括一个
valid?
测试,以便在用户完成验证解析之前不会拒绝行。允许您指定一个过程或一个符号,该符号指向一个方法,该方法检查是否应为某个属性哈希生成记录。散列被传递给提供的进程或方法,它应该返回true或false。当指定no:reject_if时,将为所有属性散列生成一条记录,这些散列没有计算为true的_destroy值。传递:all_blank而不是Proc将创建一个Proc,该Proc将拒绝所有属性都为空的记录,不包括任何_destroy的值。
accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  :reject_if => proc { |att| att[:name].blank? && attr[:description].blank? }
accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: -> { |attr| [name, description].any? &:blank? }
accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  reject_if: :all_blank