当使用双重嵌套关联时,accepts_nested_attributes_for的reject_if::all_blank如何工作? [英] How does reject_if: :all_blank for accepts_nested_attributes_for work when working with doubly nested associations?

查看:38
本文介绍了当使用双重嵌套关联时,accepts_nested_attributes_for的reject_if::all_blank如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的模型设置如下.一切正常,除了空白零件记录允许,即使所有零件和章字段都是空白.

I have my model setup as below. Everything works fine except blank part records are allowed even if all part and chapter fields are blank.

class Book < ActiveRecord::Base
  has_many :parts, inverse_of: :book
  accepts_nested_attributes_for :parts, reject_if: :all_blank
end

class Part < ActiveRecord::Base
  belongs_to :book, inverse_of: :parts
  has_many :chapters, inverse_of: :part
  accepts_nested_attributes_for :chapters, reject_if: :all_blank
end

class Chapter < ActiveRecord::Base
  belongs_to :part, inverse_of: :chapters
end

拼写代码,:all_blank被替换为proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }.因此,我用它代替了:all_blank并添加了一些调试功能.看起来正在发生的事情是该部件的chapters属性使用false响应blank?,因为它是一个实例化的哈希对象,即使它包含的全部是另一个仅包含空白值的哈希:

Spelunking the code, :all_blank gets replaced with proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }. So, I use that instead of :all_blank and add in some debugging. Looks like what is happening is the part's chapters attribute is responding to blank? with false because it is an instantiated hash object, even though all it contains is another hash that only contains blank values:

chapters_attributes: !ruby/hash:ActionController::Parameters
  '0': !ruby/hash:ActionController::Parameters
    title: ''
    text: ''

这不是要这样工作吗?

我找到了一种解决方法:

I've found a workaround:

accepts_nested_attributes_for :parts, reject_if: proc { |attributes|
  attributes.all? do |key, value|
    key == '_destroy' || value.blank? ||
        (value.is_a?(Hash) && value.all? { |key2, value2| value2.all? { |key3, value3| key3 == '_destroy' || value3.blank? } })
  end
}

但是我希望我错过了更好的方法来解决这个问题.

But I was hoping I was missing a better way to handle this.

更新1:我尝试为Hash重新定义blank?,但这会导致问题.

Update 1: I tried redefining blank? for Hash but that causes probs.

class Hash
  def blank?
    :empty? || all? { |k,v| v.blank? }
  end
end


更新2:这可以使:all_blank像我期望的那样工作,但是它很丑陋且未经充分测试.


Update 2: This makes :all_blank work as I was expecting it to, but it is ugly and not well-tested.

module ActiveRecord::NestedAttributes::ClassMethods
  REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |k, v| k == '_destroy' || v.valueless? } }
end
class Object
  alias_method :valueless?, :blank?
end
class Hash
  def valueless?
    blank? || all? { |k, v| v.valueless? }
  end
end


更新3: h!更新1中有错字.此版本确实可以正常工作.


Update 3: Doh! Update 1 had a typo in it. This version does seem to work.

class Hash
  def blank?
    empty? || all? { |k,v| v.blank? }
  end
end

这是否有太大的潜在意外后果成为可行的选择?如果这是一个不错的选择,那么此代码应放在我的应用程序中的什么位置?

Does this have too much potential for unintended consequences to be a viable option? If this is a good option, where in my app should this code live?

推荐答案

:all_blankaccepts_nested_attributes_for一起使用时,它将检查每个单独的属性,以查看其是否为空白.

When using :all_blank with accepts_nested_attributes_for, it will check each individual attribute to see if it is blank.

# From the api documentation
REJECT_ALL_BLANK_PROC = proc do |attributes|
  attributes.all? { |key, value| key == "_destroy" || value.blank? }
end

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes /ClassMethods.html

嵌套关联的属性将是一个包含关联属性的哈希.检查属性是否为空将返回false,因为哈希值不为空-它包含关联的每个属性的键.由于嵌套的关联,此行为将导致reject_if: :all_blank返回false.

The attribute of the nested association will be a hash that contains the attributes of the association. The check to see if the attribute is blank will return false because the hash is not empty - it contains a key for each attribute of the association. This behavior will cause the reject_if: :all_blank to return false because of the nested association.

要解决此问题,您可以将自己的方法添加到application_record.rb中,如下所示:

To work around this, you can add your own method to application_record.rb like so:

# Add an instance method to application_record.rb / active_record.rb
def all_blank?(attributes)
  attributes.all? do |key, value|
    key == '_destroy' || value.blank? ||
    value.is_a?(Hash) && all_blank?(value)
  end
end

# Then modify your model book.rb to call that method
accepts_nested_attributes_for :parts, reject_if: :all_blank?

这篇关于当使用双重嵌套关联时,accepts_nested_attributes_for的reject_if::all_blank如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆