【问题标题】:How to avoid nilClass errors如何避免 nilClass 错误
【发布时间】:2017-08-25 15:51:26
【问题描述】:

如果我尝试检查数据库中的值,有时会收到与我的查询没有命中相关的错误。

所以我开始使用.present? 来检查查询是否返回任何结果,然后再进行原始检查。

有没有比这更顺畅的方法来避免 nilClass 错误?

temp = Event.where(basket_id: basket.basket_id).where(event_type: ["operatorJoined", "operatorDisconnected"]).last
if temp.present? && temp.event_type == "operatorJoined"

【问题讨论】:

  • 事件和篮子有什么关系?为什么篮子有一个 basket_id 字段,这不是 Rails-y。您正在执行.last 您希望此查询返回一个或不返回对吗? temp不是一个很好的名字,也许是eventevent.present? 足够流畅,特别是如果你只做一次;这取决于您多久要求我们提供更好的解决方案。
  • 这是一个示例代码。问题是我是否可以避免要求 .present?完全没有 - 并且在单行中做到这一点更顺畅。
  • 示例代码的写法是no,因为.last会返回一个事件或者nil。你总是可以做event.try(:event_type),但这更顺畅吗?没有更多上下文很难说。
  • 如果它返回 nil(因为 .last),我希望条件为 false,而不是应用程序因 nilClass 错误而失败。我会尽力解释得更好。假设您有一个用户表。我想检查最后一个用户是否名为 Robin。 if User.last.name == "Robin" 这可以正常工作,但如果用户表为空,它将失败。你会如何检查这个?
  • 我理解你的问题很好。同样,如果您决定使用.last,请准备好处理nil.present? 是一个很好的方法。我更喜欢它而不是更简单的if temp &&,因为它更明确。如果您一次又一次地这样做,那么您可能希望以不同的方式解决这种气味,但很难通过假设来判断。

标签: ruby-on-rails rails-activerecord


【解决方案1】:

你可以写:

if temp && temp.event_type == "operatorJoined"

...或者您可能想查看 Sandy Metz 演示文稿“Nothing is Something”,以了解有关使用空对象模式避免此问题的更多信息。

我真的希望这段代码是这样的:

temp = Basket.events.operator_join_or_disc.last
if temp && temp.operator_joined?

【讨论】:

  • 由于 OP 使用的是 Rails,他可以简单地这样做:if temp.try(:event_type) == 'operatorJoined'(例如:nil.try(:something) == 'some string' 返回false
  • 是的:虽然我不是#try的粉丝。
【解决方案2】:

Ruby 2.3 引入了一个安全调用运算符(我也经常看到它被称为安全导航运算符)&.,它类似于 rails 中的 try! 方法:

class A
  attr_accessor :the_other_a

  def do_something
    puts "doing something on #{object_id}"
  end
end

a = A.new

a.do_something # => shows 'doing something on 70306921519040'
a.the_other_a.do_something # => NoMethodError: undefined method `do_something' for nil:NilClass
a.the_other_a&.do_something # => nil

a.the_other_a = A.new
a.the_other_a&.do_something # => shows 'doing something on 70306910376860'

a.the_other_a&.do_something_else # => NoMethodError: undefined method `do_something_else' for #<A:0x007fe334d62738>

a.the_other_a.try(:do_something_else) # => nil
a.the_other_a.try!(:do_something_else) # => NoMethodError: undefined method `do_something_else' for #<A:0x007fe334d62738>

因此,在您的示例中,这样的事情应该可以工作:

temp = Event.where(basket_id: basket.basket_id).where(event_type: ["operatorJoined", "operatorDisconnected"]).last
if temp&.event_type == "operatorJoined"

但是,present? 只检查!blank?,所以如果变量(在本例中为temp)可能是false''' '[]{}(在任何其他将返回trueblank? 的事物中,temp.present? &amp;&amp; temp.something_else 将与temp&amp;.something_else 不同。不适用于这种情况,因为它是 ActiveRecord 查询的结果,但需要牢记。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 2018-07-04
    • 1970-01-01
    • 2014-06-03
    • 2010-11-17
    • 2023-03-18
    相关资源
    最近更新 更多