在 Ruby on Rails 中测试模型实例是不是为“空”的最佳方法是啥?

Posted

技术标签:

【中文标题】在 Ruby on Rails 中测试模型实例是不是为“空”的最佳方法是啥?【英文标题】:Which is the best way to test if a model instance is "empty" in Ruby on Rails?在 Ruby on Rails 中测试模型实例是否为“空”的最佳方法是什么? 【发布时间】:2011-12-07 03:07:55 【问题描述】:

我想实现一个方法来检查模型的实例是否只有 nil 或空属性,除了它的 id 或时间戳

我使用了一种辅助方法,从 Hash 中删除一个键并返回剩余的哈希 (question 6227600)

class ActiveRecord::Base
    def blank?
        self.attributes.remove("id","created_at","updated_at").reject|attr| self[attr].blank?.empty?
    end
end

我想可能有更简单、有效或更安全的方法来做到这一点。有什么建议吗?

【问题讨论】:

为什么要创建空实例?当您有信息填写时,只需创建实例即可。 您是否要检查模型对象是否已更改?例如,如果用户没有输入任何内容,那么它就不会改变。 【参考方案1】:
def blank?
  self.attributes.all?|k,v| v.blank? || %w(id created_at updated_at).include?(k)
end

我的回答与 tadman 给出的几乎相同,但表达方式更简洁。 小心两种情况:

- **blank?** 不是一个好的名称选择,因为如果你调用 **object_a.object_b.blank?** 试图知道 object_a 中是否有 object_b,你会得到 true如果对象存在则事件。 **empty?** 似乎是一个更好的名字

- 如果数据库设置默认值,这可能会很棘手。

编辑:由于每次迭代都构建一个数组很慢(感谢 tadman),一个更好的解决方案是:

def empty?
  ignored_attrs = 'id' => 1, 'created_at' => 1, 'updated_at' => 1
  self.attributes.all?|k,v| v.blank? || ignored_attrs[k]
end

【讨论】:

也感谢您对方法名称的观察。我从未找到 Object#blank?非常有用,但无论如何你是对的,最好不要覆盖默认方法。 每次通过循环声明数组内联会产生显着的性能损失。您应该考虑创建一个包含您希望忽略的属性的常量,或者更好地将其转换为哈希,以便测试是 IGNORED_ATTRIBUTES[k] 而不是 ARRAY.include?(k) 确实如此,但性能不是重点。我将编辑回复:D【参考方案2】:

您可以检查 attributes 哈希中的所有属性是否不存在,或者相反:

class ActiveRecord::Base
  def blank?
    !self.attributes.find do |key, value| 
      case (key)
      when 'id', 'created_at', 'updated_at'
        false
      else
        value.present?
      end
    end
  end
end

不幸的是,如果分配了任何关系键等,这将不考虑在您的数据库中使用default 设置的内容。您必须将它们添加为异常,或将这些值与某种已知的默认状态进行比较。

这种事情可能最好根据具体情况实施。

【讨论】:

谢谢你。我只能接受一个答案,我选择 Cibernox 的答案主要是因为我更喜欢避免使用案例构造。但是,您有第一个好答案的功劳! 那么你应该重新考虑你的立场。 case 几乎是 O(1) 时间,其中 Array#include? 是 O(N) 时间。即使列表中只有几项,case 的表现也要好五倍。

以上是关于在 Ruby on Rails 中测试模型实例是不是为“空”的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails 5 Action Cable:当前模型实例的流(基于 URL 的订阅)

Ruby on Rails 生成模型

如何在 Ruby on Rails 的控制台中调用控制器/视图辅助方法?

在控制器中找不到命名空间内的 Ruby on Rails 模型

Ruby on Rails:获取模型中的下一项

Ruby on Rails 复数模型名称