首页 > 解决方案 > `detect` 和 `find` 返回 `nil` 而 `find_all` 和 `select` 返回结果

问题描述

使用下面的代码,byebug 会跳闸:

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
  if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
    byebug
  end
end

这将返回正确的结果:(编辑:此 WAS 返回正确的结果,现在返回 nil)

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
  if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
    ok = true
  end
  ok
end

然而,它只返回nil'if' 条件(没有if语句);而find_all两者select都返回一个值。

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result

  (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
end

我想知道是否有人知道该怎么做;也许是红宝石或安装失败?

标签: ruby

解决方案


有两个不同的问题:

1)为什么版本byebug不起作用

这是文档中的重要部分find返回第一个不为假的块。

现在让我们看看您的案例:

# just writing "true" here, with no if statement will deliver a result

如果你只是写true在块的末尾,那么它true会被返回,因此会find找到这个条目。

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
  ok = true
end
ok

这种情况类似:如果if条件是true您分配trueok变量。因为您ok在块的最后一行再次调用,所以块返回truefind找到该元素。

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
  byebug
end

但是你的代码中的这个例子是不同的。bundle如果if条件为,则在此处打开true。这使得bundler调用成为find块中的最后一个方法调用。调用bundler不会返回true,因此整个块不会返回true并且find不会选择这些条目。

true解决方案是在块的最后一行返回find。因为您的代码中已经有了条件,所以您可以直接使用它而无需true先分配给变量。– 例如像这样:

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result

  event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period
end

2)为什么find_allselect工作,但find没有?

在评论中,您澄清了@game_instances它实际上不是一个数组,而是一个ActiveRecord::Relation. ActiveRecord::Relation#find工作方式与Array. find在这种关系上进行简化,需要id一个记录,并在关系给定的范围内返回该记录。调用to_a关系会将所有记录加载到内存中,并允许您使用Array#find.

从性能的角度来看,将条件转换为 SQL 条件并仅加载从数据库中匹配的一条记录而不是加载所有记录并在应用程序中找到正确的记录是有意义的。


推荐阅读