迭代对象(如果存在,单个或复数)

时间:2013-12-27 13:50:41

标签: ruby-on-rails ruby

假设我有对象 my_obj

我从数据库中获取此对象,进行更多计算,无所谓......

然后我需要通过这样的对象进行迭代,例如:

my_obj.each do |m|
 some_method(m.id)
end

这段代码不好,因为如果my_obj为nil,我会得到如下错误:

undefined method `each' for nil:NilClass

所以我决定写:

  if my_obj.present?
    my_obj.each do |m|
     some_method(m.id)
    end
  end

但我认为还有另外一种方法可以做到这一点,如果构建的话,无需写到处。

所以我怎么能通过对象迭代,只有它不是null?

9 个答案:

答案 0 :(得分:5)

我发现代码对于正常的OOP原则有点反模式“告诉,不要问”。我在控制台中尝试了这个问题,发现你的担心是不必要的。

无论结果是什么,空白数组或空白的ActiveRecord :: Relation对象,each都可以工作并返回一个空白数组[]

Article.count
# => 0

articles = Article.all # Return array in Rails 3
articles.each { |a| puts a.title }
# => []

articles = Article.scoped # Return ActiveRecord::Relation object in Rails 3
articles.each { |a| puts a.title }
# => []

我建议您查看方法并返回查询结果。如果您的查询返回异常情况,请确保它至少返回一个空白数组。那你就不需要考虑太多。

答案 1 :(得分:5)

最简单的处理方法是使用'Array'转换函数来包围对象,该函数会将您可能的nil输入强制转换为数组,同时保持现有数组不受影响,例如

>> Array(nil)
=> []

>> Array([1])
=> [1]

所以在你的情况下:

Array(my_obj).each do |m|
 some_method(m.id)
end

答案 2 :(得分:3)

集合查询应始终返回可迭代对象,但有几种方法。 nil检查的问题导致了一个名为NullObjects的模式,这通常是最好的解决方案。除此之外,你可以做到:

my_object.to_a.each do |m|
  some_method(m.id)
end

my_object.try(:each) do |m|
  some_method(m.id)
end

(my_object || []).each do |m|
  some_method(m.id)
end

答案 3 :(得分:2)

在Rails中,您可以执行Object#try方法:

my_object.try(:each) do |m|
  some_method(m.id)
end

如果each不是my_object,它会使用附加块调用nil(返回其结果)。否则,它将不会调用each方法并返回nil

答案 4 :(得分:2)

你可以像这样初始化;

def fields_each(fields)
  if fields.present? && fields.keys.present?
    fields.each do |key, value|
      yield(key, value) if block_given?
    end
  end
end

和用法;

fields_each({a: 1, b: 2, c: 3}) do |key, value|
  puts "Key: #{key} value: #{value}"
end

答案 5 :(得分:1)

每个人都忘记了真棒[my_objects].flatten.compact

答案 6 :(得分:1)

在经过2.4.1测试的较新的红宝石版本中,可以写为

my_obj&.each do |m|
 some_method(m.id)
end

答案 7 :(得分:0)

初始化my_obj时,请执行此操作

my_obj = Model.all || [] # Empty array will not iterate or throw error

<强>实施例

[].each do |x|
  p "I will not execute"
end

答案 8 :(得分:0)

你可以在循环上面试试这个:

   if my_obj == nil then
    redirect_to "something_else"
   end