从数组中获取对象

时间:2016-01-31 00:19:05

标签: arrays ruby

我正在尝试访问数组中对象的属性,但我一直收到错误,说数组值为nil:

@notifications.each do |note|
  @users << User.find(note.notifier_id)
end

@unreads = []
for i in 0..@users.count
  @unreads[i] = 0
  @current_user.notifications.each do |n|
    if n.notifier_id == @users[i].id && n.seen == false
      @unreads[i] += 1
    end
  end
end

我收到错误:NoMethodError (undefined method 'id' for nil:NilClass):,来自@users[i].id

如果我没有运行for循环并打印出@users的值,我会得到预期的输出,其中包含有效的id值。

如何从阵列中正确访问User对象?

3 个答案:

答案 0 :(得分:3)

您的代码中存在两个问题。

1。一分错误

第一个问题永远是个问题。正如@sawa回答的那样,您在for循环中使用的范围内有一个一个一个错误。使用三个点:

for i in 0...@users.count

而不是两个点:

for i in 0..@users.count

Range类的Ruby 2.3.0 documentation读取:

  

使用..构建的范围包括从开始到结束。使用...创建的内容排除了结束值。

2。查询中可能存在nil结果

User.find(note.notifier_id)可能会返回nil。与问题#1不同,这可能并不总是发生。我不是假设你在下面的建议中使用Rails,因为你没有提到使用它。

解决此问题的一种方法是确保User.find 始终返回响应#id的对象。在大多数情况下,这将是User的实例,当查询无法找到User记录时,可能是空对象。您可以看到空对象模式here的示例。

解决此问题的另一种方法是在向@users[i]消息发送之前检查#id是否存在。

@notifications.each do |note|
  @users << User.find(note.notifier_id)
end

@unreads = []
for i in 0...@users.count
  @unreads[i] = 0
  @current_user.notifications.each do |n|
    if @users[i] && n.notifier_id == @users[i].id && n.seen == false
      @unreads[i] += 1
    end
  end
end

如果@users[i]nil,则代码将不会执行@users[i].id。然而,将额外检查添加到条件会使代码更难阅读。

在计算未读项目数之前,您还可以使用#compactnil数组中丢弃@users个值。我在下面使用each_with_index,因为它比for更加惯用。

@notifications.each do |note|
  @users << User.find(note.notifier_id)
end

@unreads = []
@users.compact.each_with_index do |user, i|
  @unreads[i] = 0
  @current_user.notifications.each do |n|
    if n.notifier_id == @users[i].id && n.seen == false
      @unreads[i] += 1
    end
  end
end

答案 1 :(得分:2)

您的访问方式是正确的,但您尝试访问不存在的索引@users。尝试:

for i in 0...@users.count

答案 2 :(得分:0)

来自0..@users.count

@user.count + 1个元素,但您可以通过0..(@users.count-1)的索引进行访问。 最好使用each_with_index循环@users

@users.each_with_index do |user, i|
  @unreads[i] = @current_user.
    notifications.
    where(notifier_id: user.id, seen: false).
    count
end

更短的版本

@users = User.where(id: @notifications.map(&:notifier_id)) 
@unreads = @users.map { |user| @current_user.notifications.where(notifier_id: user.id, seen: false).count }